Как сделать условный generi c тип, который имеет значение, когда оно не определено, но не когда оно не определено И еще что-то - PullRequest
3 голосов
/ 14 июля 2020

У меня есть тип, в котором я хочу определить ключ объекта как необязательный с помощью any Если я не даю никакого значения

type OptionalData<T> = T extends undefined ? { data?: any } : { data: T };

export type DataObject<T = any> = {
  item?: string | null;
} & OptionalData<T>;

Он работает нормально, пока я не установлю свой generi c как something | undefined

const data: DataObject<string | undefined> = { data: true }; // WRONG!
const data2: DataObject<string | number> = { data: true }; // CORRECT

, поскольку мой generi c также может расширять undefined Я получаю данные как необязательные any

ipt

Is there a way to say "it is just optional any when it can JUST extend undefined" or so?

Игровая площадка

1 Ответ

1 голос
/ 14 июля 2020

Проблема

У вас есть следующие типы:

type OptionalData<T> = T extends undefined ? { data?: any } : { data: T };

export type DataObject<T = any> = {
  item?: string | null;
} & OptionalData<T>;

Когда вы вводите переменную как DataObject с параметром типа, являющимся объединением типа (например, string) и undefined вы ожидаете, что свойство данных будет набрано как тип объединения, однако оно набрано как any:

const data: DataObject<string | undefined> = { data: ... }

// data.data should be typed as `string | undefined` however
// data.data is typed as `any`

Что происходит?

Документация TypeScript для условных типов здесь полезно. Он гласит:

Условные типы, в которых проверяемый тип является параметром голого типа, называются распределительными условными типами. Распределительные условные типы автоматически распределяются по типам объединения во время создания экземпляра. Например, экземпляр T extends U ? X : Y с аргументом типа A | B | C for T разрешается как (A extends U ? X : Y) | (B extends U ? X : Y) | (C extends U ? X : Y).

- Документация по распределительным условным типам

Итак, в вашем случае он разрешается до

| (string extends undefined ? { data?: any } : { data: T })
| (undefined extends undefined ? { data?: any } : { data: T })

Первое условное выражение разрешается до { data: T }, а второе разрешается до { data?: any }. Я считаю, что типы объединения будут разрешаться в тип, который является наиболее общим c, поэтому в конечном итоге тип будет { data?: any }.

Решение

Здесь OptionalData обновлено, чтобы он работал должным образом :

type OptionalData<T> = [T] extends [undefined] ? { data?: any } : { data: T };

Мы просто заключили T и undefined в квадратные скобки ([]), превратив их в кортежи (или технически монументальные, потому что у них только один элемент). Вот демонстрация .

Почему это работает?

Давайте еще раз вернемся к документации по условным типам, с некоторым дополнительным акцентом на важных частях:

Условные типы, в которых проверяемым типом является параметр голый тип , называются распределительными условными типами. Распределительные условные типы автоматически распределяются по типам объединения во время создания экземпляра.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...