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