我有一个接受类型T
作为泛型参数的类型。
在泛型函数的类型参数中,我使用Pick
从对象的键派生T
。
如果我使用一个中间类型变量来获取这些键,它就不能在函数体中充当T。如果我跳过中间变量(其他的都一样(,它的行为就像T!
操场上注释良好的例子(这是我能做的最短的(
转载如下:
//util to inspect types
type Id<T> = T extends object ? {} & { [P in keyof T]: Id<T[P]> } : T;
//-----
type AllKeys = "goodkey1" | "goodkey2" | "badkey";
type GoodKeys = "goodkey1" | "goodkey2"; //no badkey
//generic type only accepts good keys
type GenericType<T extends GoodKeys> = {
something: T
};
//an object type with ALL keys (good and bad)
type AnObjectWithAllKeys = { [key in AllKeys]: any };
export function genericFunction<
AllKeysObj extends AnObjectWithAllKeys,
//an object with only good keys:
PermittedObj extends Pick<AllKeysObj, GoodKeys>,
//should only be good keys but errors as a type argument in function body
InferredPermittedKeysError extends keyof PermittedObj,
//exactly same as above only expanded (just no intermediate type)
InferredPermittedKeysNOError extends keyof Pick<AllKeysObj, GoodKeys>,
>(
) {
//why is this one giving an error string | number | symbol' is not assignable to type 'GoodKeys'
type Err = GenericType<InferredPermittedKeysError>;
//but the equivalent one does not??
type NoErr = GenericType<InferredPermittedKeysNOError>;
//return types to inspect
return null as unknown as [InferredPermittedKeysError, InferredPermittedKeysNOError];
}
type Ret = ReturnType<typeof genericFunction>;
//hover over types and they are the same!
type ErrType = Id<Ret[0]>;
type NoErrType = Id<Ret[1]>;
这是怎么回事?
类型InferredPermittedKeysError
被定义为keyof PermittedObj
的一个子类型,而PermittedObj
是Pick<AllKeysObj, GoodKeys>
的任何子类型,这意味着它除了GoodKeys
之外还可以具有任意属性。所以InferredPermittedKeysError
可以是任意的属性名称,它不必是GoodKeys
的子类型。
例如:
- 假设
AllKeysObj
恰好等于AnObjectWithAllKeys
- 还假设
PermittedObj
是类型{goodkey1: string, goodkey2: string, foobar: string}
,它实际上是Pick<AllKeysObj, GoodKeys>
的一个子型 - 则CCD_ 16将是并集类型CCD_
- 然后假设
InferredPermittedKeysError
是类型'foobar'
,这是允许的,因为它是该并集类型的子类型 - 当然,
'foobar'
并没有扩展GoodKeys
相反,InferredPermittedKeysNOError
必须确实是GoodKeys
的一个子型,因为它被定义为keyof Pick<AllKeysObj, GoodKeys>
的一个子类型,等于类型GoodKeys
。所以事实上,你的两个泛型类型是而不是等价的;您的Id
函数在这里给出了错误的结果。
为了确认,允许以下调用,没有类型错误:
// const test: ['foobar', 'goodkey1']
const test = genericFunction<
AnObjectWithAllKeys,
{goodkey1: string, goodkey2: string, foobar: string},
'foobar',
'goodkey1'
>();
游乐场链接