Typescript: заставить тип быть «строковым литералом», а не <string> - PullRequest
2 голосов
/ 12 февраля 2020

Проблема

Есть ли способ в Typescript определить тип, который является только строковым литералом , исключая string сам по себе?

Обратите внимание, что я не говорю об определенном списке строкового литерала; для которого будет работать простое объединение типа "Value1" | "Value2" или enum. Я имею в виду любой строковый литерал, но не сам string.

Пример кода

type OnlyStringLiterals = ...; // <--- what should we put here?

const v1: OnlyStringLiterals = "hi"; // should work
const v2: OnlyStringLiterals = "bye"; // should work
// and so should be for any single string value assigned

// But:
const v3: OnlyStringLiterals = ("red" as string); // should NOT work -- it's string

Вариант использования

Я делаю Брендинг на типах в моем коде, и я передаю название бренда в качестве шаблона в родительский класс. См. Код ниже:

abstract class MyAbstractClass<
    BRAND_T extends string,
    VALUE_T = string
> {
    constructor(private readonly _value: VALUE_T) { }

    getValue(): VALUE_T { return this._value; }

    private _Brand?: BRAND_T; // required to error on the last line, as intended!
}

class FirstName extends MyAbstractClass<"FirstName"> {
}

class AdminRole extends MyAbstractClass<"AdminRole"> {
}

class SubClassWithMissedName extends MyAbstractClass<string> {
   // I want this to error! ........................ ^^^^^^
}

function printName(name: FirstName) {
    console.log(name.getValue()); 
}

const userFirstName = new FirstName("Alex");
const userRole = new AdminRole("Moderator");

printName(userRole); // Already errors, as expected

Playground Link

Я хочу убедиться, что каждый подкласс проходит точно строковый литерал , а не просто string в родительский класс.

Ответы [ 2 ]

2 голосов
/ 12 февраля 2020

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

Процесс мышления

Я считаю, что невозможно иметь один тип solid для представления того, что я хотел, потому что я даже не могу думать, что будет в VS Code, если Я намекаю на это!

Однако, насколько мне известно, в Typescript есть проверка стиля функции для типов, в которых можно передать тип и ожидать тип назад, и, наконец, присвоить ему значение, чтобы увидеть если он пройдет.

Проверка типов с использованием Generi c Type и последующее назначение

Используя эту технику, я думаю о следующем типе шаблона:

type TrueStringLiterals<T extends string> = string extends T ? never : true;

const v1 = "hi";
const check1: TrueStringLiterals<typeof v1> = true; // No error :-)

const v2 = "bye";
const check2: TrueStringLiterals<typeof v2> = true; // No error :-)

const v3 = ("red" as string);
const check3: TrueStringLiterals<typeof v3> = true; // Errors, as expected!

Playground Link

Проще в уже пройденном Generi c Тип

Кроме того, в моем случае я делаю:

abstract class MyAbstractClass<
    BRAND_T extends (string extends BRAND_T ? never : string),
    VALUE_T = string
> {
...

Playground Link

... которая работает как шарм!

0 голосов
/ 12 февраля 2020

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

type SubString<T> = T extends string ?
    string extends T ? never
    : T
    : never

const makeSubStr = <T extends string>(a: SubString<T>) => a
const a = makeSubStr('strLiteral')
const b = makeSubStr('strLiteral' as string) // error

const c: string = 'elo I am string'
const d = makeSubStr(c) // error

const e: SubString<"red"> = ("red" as string); // error

Этот тип также вернет never, если что-то не является строкой, в вашем ответе TrueStringLiterals не будет принимать Рассмотреть это дело и передать его.

...