TypeScript理解呼叫站点的条件类型但不了解使用站点?

时间:2018-04-27 21:02:18

标签: typescript

我正在尝试创建一个从传入的对象中提取字符串或数字的函数。允许调用者传入一个函数,该函数接受对象并返回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

0 个答案:

没有答案