Интерфейс не может расширить сопоставленный тип в условном типе

While debugging my program, I noticed that the following example yields a compile error (детская площадка).

type Foo = {key: string};
interface Bar {key: string};

type Baz = Foo extends Record<string, unknown>? any: never;
type Qux = Bar extends Record<string, unknown>? any: never;

const baz: Baz = 0;
const qux: Qux = 0; // Type 'number' is not assignable to type 'never'.

Кажется, интерфейсы не могут расширять Record<string, unknown>, тогда как типы могут. Я знаю, что между типами и интерфейсами в TypeScript есть несколько различий, и я подозреваю, что тот факт, что сопоставленные типы нельзя использовать в интерфейсах, может объяснить такое поведение. Я не могу полностью понять, почему это ограничение типа карты приводит к тому, что Qux становится never, даже если это так.

Кроме того, interface Foobar extends Record<string, unknown> { key: string }; является допустимым определением интерфейса, что делает ошибку более запутанной для меня.

Может ли кто-нибудь помочь мне понять эту ошибку?


person yudai-nkt    schedule 04.01.2021    source источник
comment
Я считаю, что это связано с stackoverflow.com/questions /37233735/   -  person captain-yossarian    schedule 04.01.2021


Ответы (1)


Это связано с тем, что псевдонимы типов имеют неявную сигнатуру индекса, а интерфейсы — нет.

Если вы добавите индексную сигнатуру в интерфейс - Qux приведет к any:

interface Bar { 
    key: string;
    [p: string]: string;
};

Playground

Подробнее здесь:

В настоящее время такое поведение предусмотрено дизайном. Поскольку интерфейсы могут быть дополнены дополнительными объявлениями, а псевдонимы типов — нет, безопаснее (в кавычках) выводить неявную сигнатуру индекса для псевдонимов типов, чем для интерфейсов.

person Aleksey L.    schedule 04.01.2021
comment
Этот метод можно использовать для проверки того, является ли тип интерфейсом или нет. Но не уверен, что это полезно))) - person captain-yossarian; 04.01.2021
comment
Я действительно проверил указанную проблему, но понятия не имел, что она актуальна, спасибо. Тем не менее, мой вопрос остается; почему interface Foobar extends Record<string, unknown> { key: string }; действителен? Если { key: string } в выражении является интерфейсом (а не псевдонимом типа), он не имеет сигнатуры индекса и не может быть частичным типом Record<string, unknown>, не так ли? Я мог упустить что-то фундаментальное... - person yudai-nkt; 04.01.2021
comment
@yudai-nkt Вы смешиваете расширение интерфейса typescriptlang.org/docs/ справочник/ с условными типами typescriptlang.org/docs /руководство/ - person Aleksey L.; 04.01.2021
comment
А, понял. Да, я слишком много думал и как-то перепутал эти два extends. Спасибо еще раз! - person yudai-nkt; 04.01.2021