Преобразуйте необязательные свойства интерфейса TypeScript в обнуляемые свойства - PullRequest
1 голос
/ 10 октября 2019

У меня есть следующий тип:

interface A {
  p1: string
  p2?: string
}

Я хотел бы сгенерировать подтип B с необязательными свойствами, преобразованными в обнуляемые свойства. Что-то эквивалентное:

interface B {
  p1: string
  p2: string | null
}

Я пробовал что-то вроде этого:

type VuexPick<T, K extends keyof T> = {
  [P in K]-?: T[P] extends undefined ? null : T[P];
};

type B = VuexPick<A, "p1" | "p2">;

Но это не работает. Есть идеи?

Ответы [ 2 ]

1 голос
/ 10 октября 2019

Ваш тип B разрешается следующим образом:

type B = {
  p1: string extends undefined ? null : string
  p2: string | undefined extends undefined ? null : string | undefined
};

string | undefined, поскольку супертип не распространяется undefined, наоборот. Таким образом, вы получите следующий тип:

type B = {
    p1: string;
    p2: string;
}

Вместо этого вы можете создать тип UndefinedToNull, что приведет к применению условно-распределительного условного типа , так как T является параметр обнаженного типа сейчас.

type VuexPick2<T, K extends keyof T> = {
  [P in K]-?: UndefinedToNull<T[P]>;
};

type UndefinedToNull<T> = T extends undefined ? null : T

type B2 = VuexPick2<A, "p1" | "p2">; // type B2 = { p1: string; p2: string | null;}

Например, тип UndefinedToNull<string | undefined> совпадает с B4:

type B4 = 
| (string extends undefined ? null: string) 
| (undefined extends undefined ? null: undefined) // type B4 = string | null

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

1 голос
/ 10 октября 2019

Это работает:

export type OptionalTuNullable<O> = {
  [K in keyof O]-?: undefined extends O[K] ? NonNullable<O[K]> | null : O[K];
};

Так, например:

type R = {
  a: string;
  b?: string;
  c?: string | null;
  d: string | undefined;
};

type A = OptionalTuNullable<R>;
// A: {
//     a: string;
//     b: string | null;
//     c: string | null;
//     d: string | null;
// }

Затем, для части "Pick", вы можете просто прибегнуть к стандартному типу Pick:

type B = Pick<A, "a" | "c">;
// B: {
//   a: string;
//   c: string | null;
// }

Подводя итог, я думаю, это подойдет для вашего варианта использования:

type VuexPick<T, K extends keyof T> = Pick<OptionalTuNullable<T>, K>

type C = VuexPick<R, 'c'>
// C: {
//   c: string | null;
// }

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