我正在尝试创建一个从传入的对象中提取字符串或数字的函数。允许调用者传入一个函数,该函数接受对象并返回string | number
或2)传递一个字符串或数字属性的名称。
2.8中的条件类型似乎应该能够做到这一点(而且他们会这样做!)但不幸的是,当我使用属性名称时TS不要抱怨需要通过any
进行类型断言,这似乎不正确。在函数的调用站点, 类型被正确检查,所以我认为我距离正确的答案还不远。
type RowKey = string | number;
type RowKeyableNames<T> = { [K in keyof T]: T[K] extends RowKey ? K : never }[keyof T];
type RowKeyable<T> = Pick<T, RowKeyableNames<T>>;
type RowKeySel<T> = { (val: T): RowKey; } | RowKeyableNames<T>;
const getRowKey = <T extends {}>(val: T, sel: RowKeySel<T>): RowKey => {
if (typeof sel === 'function') {
return sel(val);
} else {
// This shouldn't error, but it does! See error message below.
return val[sel];
}
}
interface Foo {
id: number;
name: string;
contents: any[];
}
function myThing(foo: Foo): RowKey {
// works, like it should.
getRowKey(foo, 'id');
getRowKey(foo, 'name');
// errors, like it should! That's what we want.
getRowKey(foo, 'contents');
}
我收到的错误消息是:
Type 'RowKey[] | T[{ [K in keyof T]: T[K] extends RowKey ? K : never; }[keyof T]][]' is not assignable to type 'RowKey[]'.
Type 'T[{ [K in keyof T]: T[K] extends RowKey ? K : never; }[keyof T]][]' is not assignable to type 'RowKey[]'.
Type 'T[{ [K in keyof T]: T[K] extends RowKey ? K : never; }[keyof T]]' is not assignable to type 'RowKey'.
Type 'T[{ [K in keyof T]: T[K] extends RowKey ? K : never; }[keyof T]]' is not assignable to type 'number'.
我希望避免双重断言(as any as RowKey
),但我可能不得不走那条路。
问题是:如果没有双重类型断言,我需要RowKeySel<T>
的类型才能使其工作?
编辑:我最好的猜测是T
的其他键并未真正被此条件类型删除,它们只是设置为never
。因此,val[sel]
可能(??)被解释为string | number | never
?