TypeScript: различение объединения от значения в кортеже - PullRequest
0 голосов
/ 31 октября 2018

Можно ли различить тип объединения на основе первого элемента в свойстве кортежа?

, например

type Landing = {
  tokens: ['landing']
};

type Month = {
  tokens: ['month', string]
};

type Day = {
  tokens: ['day', string, string]
};

type Route =
  | Month
  | Day
  | Landing;

let route: Route = getRoute();

if(route.tokens[0] === 'day') {
  // resolve to Day type
}

UPDATE: Если бы не было прямого способа сделать это, я был бы счастлив с защитой нестандартного типа, но пока не смог бы заставить ее работать. Чтобы уточнить, я бы хотел, чтобы типограф защищал объединение, а не явно проверял каждый вариант.

, например

if(typeGuard(route, 'day')) {
    // compiler knows this id Day type
}
else if(typeGuard(route, 'month')) {
    // compiler knows this is Month type
}

Ответы [ 2 ]

0 голосов
/ 31 октября 2018

Редактировать После первоначального ответа машинописный текст стал лучше распознавать союзы, поэтому с машинописным шрифтом 3.3 это работает, как и ожидалось:

if (route.tokens[0] === "day") {
    // resolve to Day type
    route.tokens[0] === 'day'
} else if (route.tokens[0] === "landing") {
    // resolve to Landing type
    route.tokens[0] === 'landing'
} else {
    // resolve to Month type
    route.tokens[0] === 'month'
}

Orignial

Хотя решение по написанию type-guard для каждого члена профсоюза является вполне допустимым, оно создает проблемы, если в объединении много членов, или если позже вы добавите дополнительные члены в объединение.

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

type Landing = {
    tokens: ['landing']
};

type Month = {
    tokens: ['month', string]
};

type Day = {
    tokens: ['day', string, string]
};

type Route =
    | Month
    | Day
    | Landing;

declare let route: Route;

function isRoute<T extends Route['tokens'][0]>(r: Route, type: T): r is Extract<Route, { tokens: [T, ...any[]] }> {
    return route.tokens[0] === type;
}

if (isRoute(route, 'day')) {
    // resolve to Day type
    route.tokens[0] === 'day'
} else if (isRoute(route, 'landing')) {
    // resolve to Landing type
    route.tokens[0] === 'landing'
} else {
    // resolve to Month type
    route.tokens[0] === 'month'
}

Ссылка на игровую площадку

0 голосов
/ 31 октября 2018

Используя typeguards, это будет примерно так:

type Landing = {
  tokens: ['landing']
};
const isLanding = (x: any): x is Landing => x[0] === 'landing'

type Month = {
  tokens: ['month', string]
};
const isMonth = (x: any): x is Month => x[0] === 'month'

type Day = {
  tokens: ['day', string, string]
};
const isDay = (x: any): x is Day => x[0] === 'day'

type Route =
  | Month
  | Day
  | Landing;

let route: Route = getRoute();

if(isDay (route)) {
  // resolve to Day type
}

Вы можете найти больше информации о типе guard в официальной документации (поиск типа guard)

надеется, что ответ на ваш вопрос;)

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