Typescript - определение типов значений на основе предоставленного ключа объекта - PullRequest
0 голосов
/ 01 июля 2019

Учитывая, что у меня есть тип как:

type Foo = {
  foo: number;
  bar: string;
  baz: boolean;
}

Я хочу иметь тип Buzz, который может определять тип значения по ключу, то есть

const abc: Buzz<Foo> = {
  key: 'foo',
  formatter: (detectMe) => {} //I want TS to infer this to be 'number'
};

Учитываяключ 'foo' аргумент в форматере должен быть равен number.Я попробовал это:

interface ColumnDescription<T> {
  label: string;
  key: keyof T;
  formatter?: (datum: T[keyof T]) => void;
}

Однако это приводит к выводу аргумента как number | string | boolean.

Также пробовал это:

interface ColumnDescription<T, K extends keyof T> {
  label: string;
  key: K;
  formatter?: (datum: T[K]) => void;
}

Этот видработает, но мне всегда нужно указывать ключ во втором типе аргумента, вместо того, чтобы это происходило автоматически.т.е.:

const abc: Buzz<Foo, 'foo'> = { //I don't want to specify the key
  key: 'foo',
  formatter: (detectMe) => {} //This is inferred correctly
};

1 Ответ

2 голосов
/ 01 июля 2019

Как и в моем комментарии, я бы предложил

type Buzz<T> = {
  [K in keyof T]-?: { key: K; formatter: (d: T[K]) => void }
}[keyof T];

, что похоже на то, что вы сделали с Buzz<T, K extends keyof T>, но вместо того, чтобы Buzz нужно было указать K, я использовал сопоставленный тип {[K in keyof T]: ...}, который автоматически перебирает ключи в keyof T и создает новый объект с теми же ключами, но значениями свойств которого являются искомые типы.Это означает, что для получения желаемого значения Buzz<T> нам нужно найти значений свойств, указав в нем значение [keyof T].Это делает Buzz<T> объединение типов, где каждая составляющая объединения соответствует вашему Buzz<T, K extends keyof T> для определенного ключа K

Давайте удостоверимся, что он работает:

const abc: Buzz<Foo> = {
  key: "foo",
  formatter: detectMe => {} // inferred as number, as desired
};

Выглядит хорошо, и давайте проверим тип abc с IntelliSense:

const abc: {
    key: "foo";
    formatter: (d: number) => void;
} | {
    key: "bar";
    formatter: (d: string) => void;
} | {
    key: "baz";
    formatter: (d: boolean) => void;
}

Это тоже хорошо выглядит.

Хорошо, надеюсь, это поможет;удачи!

Ссылка на код

...