Условный тип Typescript - реализовать функцию изменения типа - PullRequest
1 голос
/ 14 апреля 2019

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

type A = {
   myProp: string;
   otherProp?: number;
}

type B = {
   coolProp?: boolean[];
   someProp: SomeOtherType[];
}

редактировать: Теперь я реализовал функцию, которая принимает такой объект и имя свойства и возвращает это свойство таким, каким оно было, за одним исключением: если свойство НЕ является необязательным и НЕ является массивом, оно возвращает это свойство как массив с исходным типом в качестве типа массива.

Теперь я реализовал функцию, которая принимает такой объект и имя свойства и возвращает это свойство таким, каким оно было, за одним исключением: если свойство НЕ является массивом, оно возвращает это свойство в виде массива с исходный тип как тип массива.

Так, например, свойства из типа B сверху не изменились бы, но myProp: string; из типа A станет: myProp: string[];. otherProp?: number также останется прежним.

Так, например, свойства из типа B сверху не изменятся, но myProp: string; из типа A станет: myProp: string[];. otherProp?: number станет otherProp?: number[].

Теперь я хочу поместить это поведение в определение типа возвращаемого значения в интерфейсе, но я не могу понять, как заставить это работать.

Моя лучшая попытка была:

getPropFromObject<O, P extends keyof O>(node: O, propName: P):
    any[] extends O[P] ? O[P] : O[P] extends undefined ? O[P] : O[P][]

, но он терпит неудачу для отдельных дополнительных реквизитов, таких как otherProp?: number;

Как будет выглядеть правильное определение типа?

1 Ответ

0 голосов
/ 15 апреля 2019

Типовое отношение при работе с профсоюзами может быть обратным тому, что вы ожидаете.Союз является базовым типом для любого из его членов.Так, например:

type N = number | undefined extends undefined ? "Y" : "N" //No, the union does not extend a member
type Y = undefined extends number | undefined  ? "Y" : "N" // Yes the union extends a member

Поначалу это может показаться удивительным, но если вы относитесь к типам с точки зрения множеств, это имеет смысл.Базовый тип - это набор, который включает в себя все наборы, представляющие подтип (в конце концов, любой экземпляр подтипа также должен быть экземпляром базового типа).

Итак, возвращаясь к вашему вопросу, если вы хотите проверить, находится ли undefined в союзе с другими типами для свойства, вам нужно написать: undefined extends O[P]

declare function getPropFromObject<O, P extends keyof O>(node: O, propName: P):
    any[] extends O[P] ? O[P] : undefined extends O[P] ? O[P] : O[P][]

type A = {
    myProp: string;
    otherProp?: number;
}

getPropFromObject(null as any as A, "otherProp") // number | undefined
getPropFromObject(null as any as A, "myProp") // string[]

Редактировать

После изменения в вопросе для достижения желаемого эффекта вы можете использовать дистрибутивный условный тип .Это будет распространяться на объединения, такие как number | undefined, с условным типом, применяемым к каждому члену объединения.

type ToArray<T> = T extends unknown ? T extends undefined ? T : T[] : never;
declare function getPropFromObject<O, P extends keyof O>(node: O, propName: P):
    any[] extends O[P] ? O[P] : ToArray<O[P]>

type A = {
    myProp: string;
    otherProp?: number;
}

getPropFromObject(null as any as A, "otherProp") // number[] | undefined
getPropFromObject(null as any as A, "myProp") // string[]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...