#typescript #typescript-generics
#typescript #typescript-дженерики
Вопрос:
Использование расширения keyof некоторого типа объекта отлично работает для индексации этого типа, но не работает с расширением типа объекта. Есть ли способ сообщить TypeScript, что типы должны работать, это ошибка или я что-то упускаю?
type Foo = { bar(a: string): boolean }
// works
type Thing1<F extends keyof Foo> = ReturnType<Foo[F]>
// doesn't work:
type Thing2<Fo extends Foo, F extends keyof Fo> = ReturnType<Fo[F]>
ошибка ts:
Type 'Fo[F]' does not satisfy the constraint '(...args: any) => any'.
Type 'Fo[keyof Fo]' is not assignable to type '(...args: any) => any'.
Type 'Fo[string] | Fo[number] | Fo[symbol]' is not assignable to type '(...args: any) => any'.
Type 'Fo[string]' is not assignable to type '(...args: any) => any'.(2344)
Вот что я пытаюсь сделать: ссылка на игровую площадку
Комментарии:
1. Что не так с
type Thing2<Fo extends Foo, F extends keyof Foo> = ReturnType<Fo[F]>
? У вас есть сценарий, который не работает в этом случае?2. Возможно, я вас неправильно понимаю, но, согласно демонстрации playground, это не печатается. TypeScript выдает ошибку.
3. Делает для меня, typescriptlang.org/play ? #code/ …
4. ах, я пропустил ваш дополнительный o в Foo.
5. Я предполагаю, что TypeScript ничего не знает о возможных ключах
Fo
, поэтому он не позволит вам использовать его во втором ограничении.
Ответ №1:
Компилятор TypeScript понятия не имеет, какие ключи находятся на чем-то, что расширяет Foo, и все ли они являются функциями с возвращаемым типом, поэтому if не позволит вам это сделать.
Взгляните на этот пример, Foo
это нормально, потому что у него есть ключи метода, Foo2
не потому, что у него есть ключ, не являющийся ключом метода, и Foo3
все в порядке, потому что у него также есть все ключи метода. Foo2
и Foo3
являются продолжениями Foo
export type Foo = { bar(a: string): boolean; }
export type Foo2 = Foo amp; { value: string }
export type Foo3 = Foo amp; { bar2(a: number): string; }
// works
type Thing1<F extends keyof Foo> = ReturnType<Foo[F]>
// error!
type Thing2<F extends keyof Foo2> = ReturnType<Foo2[F]>
// works
type Thing3<F extends keyof Foo3> = ReturnType<Foo3[F]>
Если вы попытаетесь ввести противопоставление ключей расширению, вы можете легко передать Foo2
и ключ, на Foo2
котором не было бы a ReturnValue
.
Вот причина, по которой ваш пример возвращает ошибку типа.
Как я уже говорил в комментариях, вы можете ограничить свои ключи основным типом, и он будет работать.
type Thing3<Fo extends Foo, F extends keyof Foo> = ReturnType<Fo[F]>
Однако вы можете заставить это работать, добавив другое ограничение, в котором говорится, что все ключи объекта должны быть методом. Вам даже не нужен исходный тип.
type Thing<Foo extends Record<Bar, (...args: any) => any>, Bar extends keyof Foo> = ReturnType<Foo[Bar]>
Комментарии:
1. спасибо за объяснение! добавлена ссылка на игровую площадку к исходному вопросу, иллюстрирующая, что я пытаюсь сделать и где она ломается
2. Круто, я посмотрю и посмотрю, смогу ли я помочь.
3. вау, я думаю, что ваше последнее предложение с другим ограничением может быть решением! действительно аккуратно … не придумал бы этого!
4. Если у вас все еще возникают проблемы, дайте мне знать, каков ожидаемый результат вашей функции reduce, и я посмотрю еще раз.
5. У вас есть какие-либо идеи, почему это не работает: gist.github.com/willium/0e4aa3d24ba52080a2a73e7367519b19