打字稿多泛型对象声明
Typescript multi generics object declaration
我正在努力输入具有这种行为的函数:
给定一个对象 conf
具有未定义数量的键,每个键都是具有 value
和 type
属性的对象,该函数应该 return 具有相同属性且仅value
作为 value
.
所以要清楚,这是一个函数输入的例子:
{
foo: {value: 1, type: 'number'},
bar: {value: 'hello', type: 'string'}
}
和对应的输出:
{
foo: 1,
bar: 'hello'
}
以下是我到目前为止所写的内容:
type TypeWithName<T extends string> =
T extends 'number' ? number :
T extends 'boolean' ? boolean :
T extends 'undefined' ? undefined :
T extends 'array' ? string[] :
string
declare function f<T extends string>(conf: {
[key: string]: { default: TypeWithName<T>; type: T }
}): { [P in keyof typeof conf]: TypeWithName<T> }
这显然是不正确的,因为 :
- T一次只能取一个类型(上面的例子会在属性
bar
上抛出错误)
- return 类型具有未定义数量的键,而不是输入对象中存在的所有且唯一的键。
但我有点迷路了,真的不知道去哪里找,甚至不知道该去哪里找。
您可以尝试以下方法:
const conf = {
foo: { value: 1, type: "number" },
bar: { value: "hello", type: "string" }
};
type Input = {
[key: string]: { value: any; type: string };
};
type Output<U extends Input> = { [Key in keyof U]: U[Key]["value"] };
function f<T extends Input>(input: T): Output<T> {
// Details...
}
const returned = f(conf);
returned.foo // number
returned.bar // string
我认为这应该足够了.....关键是使用'any'
function change(x:any) {
let y:any={};
for(let c in x){
console.log(c)
y[c] = x[c].value;
}
return y;
}
let x={
'foo': {value: 1, type: 'number'},
'bar': {value: 'hello', type: 'string'}
};
console.log(change(x));
我的方法是使用从 type
属性 字符串到 value
类型的映射接口而不是条件类型;您可以在此处使用条件类型,但在类型系统中使用接口更容易:
interface TypeMap {
number: number;
boolean: boolean;
undefined: undefined;
string: string;
object: object | null;
}
我假设您希望 "string"
映射到 string
,然后我添加了 "object"
。如果你想 "array"
映射到 string[]
你可以这样做,我想。
然后我想用TypeMap
做一个联合类型Config
代表value
和type
之间的约束,像这样:
type Config = {
[K in keyof TypeMap]: { value: TypeMap[K]; type: K }
}[keyof TypeMap];
如果你检查它,它相当于:
type Config = {
value: number;
type: "number";
} | {
value: boolean;
type: "boolean";
} | {
value: undefined;
type: "undefined";
} | {
value: string;
type: "string";
} | {
value: object | null;
type: "object";
}
现在 f
函数在 T
中是泛型的,一个对象类型,其键是 whatever,其属性是 Config
,由约束 Record<keyof T, Config>
表示。输入类型为T
,输出类型maps每个属性 in T
到其value
属性:
declare function f<T extends Record<keyof T, Config>>(
t: T
): { [K in keyof T]: T[K]["value"] };
让我们看看它是否有效:
const output = f({
foo: { value: 1, type: "number" },
bar: { value: "hello", type: "string" }
});
// const output: { foo: number; bar: string; }
我认为这就是您期望的输出类型,对吧?如果您需要更窄的类型(例如,foo
是 类型 1
而不是 number
),您可以使用 const
assertion 在输入中:
const outputNarrower = f({
foo: { value: 1, type: "number" },
bar: { value: "hello", type: "string" }
} as const);
// const outputNarrower: { foo: 1; bar: "hello"; }
最后,您可以看到 f()
的输入受到限制,因此您不能给出不匹配的 value
/type
对:
f({
chicken: { value: 123, type: "string" }, // error!
cow: { value: "abc", type: "string" }
});
好的,希望对您有所帮助;祝你好运!
我正在努力输入具有这种行为的函数:
给定一个对象 conf
具有未定义数量的键,每个键都是具有 value
和 type
属性的对象,该函数应该 return 具有相同属性且仅value
作为 value
.
所以要清楚,这是一个函数输入的例子:
{
foo: {value: 1, type: 'number'},
bar: {value: 'hello', type: 'string'}
}
和对应的输出:
{
foo: 1,
bar: 'hello'
}
以下是我到目前为止所写的内容:
type TypeWithName<T extends string> =
T extends 'number' ? number :
T extends 'boolean' ? boolean :
T extends 'undefined' ? undefined :
T extends 'array' ? string[] :
string
declare function f<T extends string>(conf: {
[key: string]: { default: TypeWithName<T>; type: T }
}): { [P in keyof typeof conf]: TypeWithName<T> }
这显然是不正确的,因为 :
- T一次只能取一个类型(上面的例子会在属性
bar
上抛出错误) - return 类型具有未定义数量的键,而不是输入对象中存在的所有且唯一的键。
但我有点迷路了,真的不知道去哪里找,甚至不知道该去哪里找。
您可以尝试以下方法:
const conf = {
foo: { value: 1, type: "number" },
bar: { value: "hello", type: "string" }
};
type Input = {
[key: string]: { value: any; type: string };
};
type Output<U extends Input> = { [Key in keyof U]: U[Key]["value"] };
function f<T extends Input>(input: T): Output<T> {
// Details...
}
const returned = f(conf);
returned.foo // number
returned.bar // string
我认为这应该足够了.....关键是使用'any'
function change(x:any) {
let y:any={};
for(let c in x){
console.log(c)
y[c] = x[c].value;
}
return y;
}
let x={
'foo': {value: 1, type: 'number'},
'bar': {value: 'hello', type: 'string'}
};
console.log(change(x));
我的方法是使用从 type
属性 字符串到 value
类型的映射接口而不是条件类型;您可以在此处使用条件类型,但在类型系统中使用接口更容易:
interface TypeMap {
number: number;
boolean: boolean;
undefined: undefined;
string: string;
object: object | null;
}
我假设您希望 "string"
映射到 string
,然后我添加了 "object"
。如果你想 "array"
映射到 string[]
你可以这样做,我想。
然后我想用TypeMap
做一个联合类型Config
代表value
和type
之间的约束,像这样:
type Config = {
[K in keyof TypeMap]: { value: TypeMap[K]; type: K }
}[keyof TypeMap];
如果你检查它,它相当于:
type Config = {
value: number;
type: "number";
} | {
value: boolean;
type: "boolean";
} | {
value: undefined;
type: "undefined";
} | {
value: string;
type: "string";
} | {
value: object | null;
type: "object";
}
现在 f
函数在 T
中是泛型的,一个对象类型,其键是 whatever,其属性是 Config
,由约束 Record<keyof T, Config>
表示。输入类型为T
,输出类型maps每个属性 in T
到其value
属性:
declare function f<T extends Record<keyof T, Config>>(
t: T
): { [K in keyof T]: T[K]["value"] };
让我们看看它是否有效:
const output = f({
foo: { value: 1, type: "number" },
bar: { value: "hello", type: "string" }
});
// const output: { foo: number; bar: string; }
我认为这就是您期望的输出类型,对吧?如果您需要更窄的类型(例如,foo
是 类型 1
而不是 number
),您可以使用 const
assertion 在输入中:
const outputNarrower = f({
foo: { value: 1, type: "number" },
bar: { value: "hello", type: "string" }
} as const);
// const outputNarrower: { foo: 1; bar: "hello"; }
最后,您可以看到 f()
的输入受到限制,因此您不能给出不匹配的 value
/type
对:
f({
chicken: { value: 123, type: "string" }, // error!
cow: { value: "abc", type: "string" }
});
好的,希望对您有所帮助;祝你好运!