TypeScript объединение строк и строковых литералов - PullRequest
0 голосов
/ 05 апреля 2020

Я хотел бы создать определение типа для одного из известных строковых литералов или любой строки , например:

type IColor = "blue" | "green" | "red" | string;

TS не жалуется на это определение типа, но это также не помогает с intellisense. Моя цель - определить функцию, которая принимает один из известных цветов или любую цветовую строку.

const knownColors = {
    green: "#66bb6a",
    red: "#ef9a9a",
    blue: "#81d4fa",
} as const;

function getColor(color: keyof typeof knownColors | string): string {
   if (color in knownColors) 
      return knownColors[color as keyof typeof knownColors];

   return color;
}

Использование:

getColor("blue");    // "blue" is a known color, returns "#81d4fa" 
getColor("black");   // "black" is not a known color, returns "black"

Я хочу, чтобы intellisense было умный

getColor("_          // as I type this line, 
          ^ blue     // I want these suggestions
          ^ green
          ^ red 

1 Ответ

3 голосов
/ 05 апреля 2020

В настоящее время это считается ограничением дизайна (см. microsoft / TypeScript # 29729 ) и / или отсутствующей функцией (см. microsoft / TypeScript # 33471 ) TypeScript. С точки зрения системы типов, string - это супертип любого строкового литерала, такого как "blue" или "red", поэтому объединение string | "blue" | "red" совпадает с string, и компилятор агрессивно уменьшает такие объединения до string. Это абсолютно правильно в отношении безопасности типов. Но это не очень хорошо с точки зрения документации или IntelliSense, как вы видели.

К счастью, связанные проблемы TypeScript предлагают некоторые обходные пути, которые могут оказаться полезными. Одним из них является представление типа объединения таким образом, чтобы компилятор не уменьшал его. Тип string & {} концептуально совпадает с string, поскольку пустой тип {} соответствует любому типу, отличному от null и -undefined. Но компилятор не выполняет это сокращение (по крайней мере, в TS 3.8). Из этого типа вы можете построить свой союз как (string & {}) | "red" | "green" | "blue", и компилятор будет сохранять это представление достаточно долго, чтобы дать вам подсказки IntelliSense:

function getColor(color: (keyof typeof knownColors) | (string & {})): string {
    if (color in knownColors)
        return knownColors[color as keyof typeof knownColors];
    return color;
}

Это принимает и отклоняет те же входные данные, что и раньше:

getColor("red"); // okay
getColor("mauve"); // okay
getColor(123); // error

Но вы можете убедиться, что IntelliSense производит следующее:

IntelliSense suggesting


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

function getColorOvld(color: (keyof typeof knownColors)): string;
function getColorOvld(color: string): string;
function getColorOvld(color: string): string {
    if (color in knownColors)
        return knownColors[color as keyof typeof knownColors];
    return color;
}

getColorOvld("red"); // okay
getColorOvld("mauve"); // okay
getColorOvld(123); // error

Это также дает вам разумный IntelliSense:

enter image description here


Хорошо, надеюсь, это поможет!

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

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