Почему интерфейс не может напрямую расширять индексированный тип доступа?

У меня есть тип и интерфейс, который его расширяет:

type IntrinisicDivProps = JSX.IntrinsicElements['div'];

interface SomeComponentProps extends IntrinisicDivProps {
  // added properties
}

Это прекрасно работает. Однако мне кажется, что мне не нужно делать тип IntrinisicDivProps. В конце концов, я, по сути, говорю: «A = B, расширяется от B», так не должен ли я иметь возможность сказать «продолжается от A непосредственно»?

Я ожидал, что это сработает:

interface SomeComponentProps extends JSX.IntrinsicElements['div'] {
  // added properties
}

... но это не так. Я получил:

An interface can only extend an identifier/qualified-name with optional type arguments.ts(2499)

Как у моего IntrinisicDivProps есть «аргументы необязательного типа», а у JSX.IntrinsicElements['div'] нет, хотя один буквально = другой:

type IntrinisicDivProps = JSX.IntrinsicElements['div'];

Разве это не одно и то же?

Вероятно, было бы яснее «Интерфейс не может расширять выражение». «Как мой IntrinisicDivProps имеет «аргументы необязательного типа»» — это не так, но идентификатор или квалифицированное имя могут.
jonrsharpe 17.05.2024 23:29

Думайте об этом как об ограничении синтаксиса, а не семантического ограничения. Есть открытый вопрос... ой, посмотрите, @jonrsharpe только что связал его. Хорошо, он может написать ответ...

jcalz 17.05.2024 23:30

Если я правильно понимаю, это проблема «ТС тупой»? TS видит выражение и выдает ошибку, поскольку знает, что выражения могут содержать нерасширяемые элементы (например, идентификатор или полное имя)... хотя мое конкретное выражение этого не делает. Помещение его в переменную типа каким-то образом сообщает TS, что «это выражение не имеет идентификаторов или квалифицированных имен»?

machineghost 17.05.2024 23:46

Конечно, говоря «тупой», я просто имел в виду, что инструмент не способен понять содержимое выражения… Я не пытаюсь оскорбить TypeScript :)

machineghost 18.05.2024 00:19

Конечно, ТС неспособен этого «понять»; это синтаксическое ограничение. Вы можете расширять именованные типы, включая универсальные именованные типы, а не выражения произвольных типов. Некоторые именованные типы по-прежнему не являются расширяемыми (например, type A = {a: string} | {b: number}; interface C extends A {} не удастся). Это нереализованная функция. Проблема, указанная выше, является каноническим ответом на этот вопрос. Достаточно ли этого, если кто-то это напишет? Или мы еще что-то упускаем в этом вопросе?

jcalz 18.05.2024 03:00

Кажется, я понял: до того, как я поместил его в type, выражение было просто выражением, но после того, как я поместил его в type, это именованный тип. Синтаксически TS написан просто для того, чтобы позволить вам расширять именованные типы, а не расширения (вероятно, потому, что было бы что-то запутанное в разрешении выражений?). Другими словами, в TS после того, как вы сделаете type x = y, x !== y (потому что в этот момент x — это тип, а y — выражение). Если я прав, более или менее, мне просто нужен ответ, чтобы принять :)

machineghost 18.05.2024 06:53
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
1
6
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Это недостающая функция TypeScript, запрошенная по адресу microsoft/TypeScript#31843 . В настоящее время существует синтаксическое ограничение на то, какие типы типов могут быть расширены интерфейсом. Это означает, что даже если два типа семантически идентичны, они могут обрабатываться по-разному, если они написаны с разным синтаксисом. Синтаксически вы можете расширить только «идентификатор/полное имя с необязательными аргументами типа», что в основном означает, что он должен быть именованным типом (где «аргументы необязательного типа» означают, что это может быть именованный общий тип как ну.) Это синтаксическое ограничение ни для чего не требуется, поэтому указанный выше запрос на функцию открыт, а не отклонен. Но так обстоит дело в настоящее время.

Но это означает, что вы всегда можете обойти это ограничение, используя простой псевдоним общего типа

type Named<T> = T;

И это работает, потому что теперь синтаксически запрещенный тип становится аргументом типа, который разрешен:

interface SomeComponentProps extends Named<JSX.IntrinsicElements['div']> {
}

Обратите внимание, что это не позволяет вам обойти семантическое ограничение только на расширение типов объектов или пересечений типов объектов со статически известными членами (как это реализовано в microsoft/TypeScript#13604):

interface Oops extends Named<{ a: 0 } | { b: 1 }> { } // error, union
interface Whoops<T> extends Named<T> { }// error, unknown properties
interface Nope<T> extends Named<
  T extends string ? { a: 0 } : { b: 1 }
> { } // error, generic conditional

Детская площадка, ссылка на код

Другие вопросы по теме