TypeScript понимает условный тип на сайте вызова, но не на сайте использования? - PullRequest
0 голосов
/ 28 апреля 2018

Я пытаюсь создать функцию, которая будет извлекать строку или число из переданного объекта. Вызывающей стороне разрешено либо 1) передать функцию, которая принимает объект и возвращает 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?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...