Как получить литералы из необязательного параметра объекта - PullRequest
0 голосов
/ 19 июня 2019

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

const dd = ['a', 'b'] as const;
function cba<T extends readonly string[]>(a: { b: T }) {
  return (1 as any) as typeof a.b[number];
}

const a = cba({ b: dd });
const b = cba({ b: ['a', 's']});

Переменная a, возвращающая 'a' | 'b' тип, переменная b, возвращающая string тип, что я и хотел. Есть ли способ сделать свойство b необязательным, а затем вернуть литералы выше, если существует, и string, если нет? Вот что я пытался:

function cba<T extends readonly string[]>(a: { b?: T }) {
  return (1 as any) as typeof a.b extends 'undefined' ? string : typeof a.b[number];
}

но он возвращает ошибку ts на детали typeof a.b[number] с информацией о том, что число не может быть применено к T | undefined. Я также пробовал решения JS, чтобы проверить, существует ли свойство b:

function cba<T extends readonly string[]>(a: { b?: T }) {
  const d = a.b;
  if (d) return (1 as any) as typeof d[number];
  else return (1 as any) as string;
}

но тогда он всегда возвращает string | undefined тип. Есть идеи?

PS. (1 as any) часть не важна для этого вопроса.

1 Ответ

0 голосов
/ 19 июня 2019

Для этого можно использовать условные типы:

type Values<T extends readonly string[] | undefined> =
    T extends readonly string[] ? T[number] : undefined;

const dd = ['a', 'b'] as const;
function cba<T extends readonly string[] | undefined>(a: { b?: T }) {
  return (1 as unknown) as Values<T>;
}

const a = cba({ b: dd }); // "a" | "b"
const b = cba({ b: ['a', 's']}); // string
const c = cba({}); // string | undefined
...