Типовое утверждение общего типа - PullRequest
0 голосов
/ 30 марта 2019

Итак, вот краткий обзор моих наблюдений за работой с машинописью.

Вот код:

type someTypeEnum = '1';
type someOtherTypeEnum = '2' | '3';
type combinedTypeEnum = someTypeEnum | someOtherTypeEnum;

Вот первый случай: -

function typeAssertion<T extends combinedTypeEnum>(args: T): args is someTypeEnum {
    // The error i get
    // A type predicate's type must be assignable to its parameter's type.
    //  Type '"1"' is not assignable to type 'T'.
    return undefined;
}

Я не могу понять, почему эта вещь терпит неудачу, потому что мы уже ограничили наши аргументы для комбинированного типа, в случае, если мы делаем

typeAssertion('4')

Мы уже получаем сообщение о том, что '4' не является допустимым аргументом, поэтому почему args is someTypeEnum считается недействительным предикатом.

Вот второй случай: -

function typeAssertion(args: combinedTypeEnum): args is someTypeEnum {
    return undefined;
}

Кажется, это работает нормально, но в случае, если мы сделаем это: -

function someFunction<T extends combinedTypeEnum>(args: T): T {
    if (typeAssertion(args)) {
        // args here is  'T & "1"' 
        args
    }
    return args
};

почему у нас есть T & "1", а не только "1", мы специально утверждали, что это someTypeEnum.

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

1 Ответ

1 голос
/ 30 марта 2019

extends не имеет большого смысла, когда у вас есть строковые литералы. Чтобы облегчить объяснение, позвольте мне использовать другие типы. Рассмотрим эти три класса:

class Animal {}

class Dog extends Animal {}

class Cat extends Animal {}

когда мы используем дженерики, фактический тип устанавливается вызывающей стороной:

function foo<T extends Animal>(arg: T) {}

foo(new Dog()); //T is Dog, equivalent to foo(arg: Dog) {}
foo(new Cat()); //T is Cat, equivalent to foo(arg: Cat) {}

Теперь вы уже можете видеть, куда мы идем. Давайте использовать предикат типа:

function foo<T extends Animal>(arg: T): arg is Cat {}

Когда мы вызываем foo(new Dog()), последний пример становится эквивалентным этому:

function foo(arg: Dog): arg is Cat {}

И, конечно, это не работает или не имеет смысла.

Что касается вашего второго примера: тип переменной не изменяется. Дело в том, что, утверждая определенный тип, компилятор позволяет вам делать все, что можно сделать с этим типом.

...