Как TypeScript определяет тип `this`? - PullRequest
       63

Как TypeScript определяет тип `this`?

0 голосов
/ 09 сентября 2018

Стратегия вывода this в TypeScript меня смущает, например:

class A {
    s: String
    constructor() {
        this.s = "this is fine"
    }
    f() {
        console.log(this.s)
    }
}

let a = new A

a.f() // -> this is fine

let f1 = (new A).f
f1() // -> undefined

Если вы поместите код в TypeScript Playground и проверите тип this внутри f(), вы увидите, что он имеет тип this: this, что означает подтип A.

В этой ситуации, я думаю, это означает, что this привязан к A и не может ссылаться на глобальный объект. В противном случае this должен быть выведен как тип this: Any.

Но на самом деле, как показано в вызове f1(), если функция f вызывается вне контекста A, она все равно может быть глобальным объектом.

Так что, по моему мнению, предполагаемый тип this внутри f() должен быть this: Any, а не this: this. И только если функция f определена с помощью функции стрелки, можно сделать вывод, что она будет this: this. Например:

class A {
    s: String
    constructor() {
        this.s = "this is fine"
    }
    f = () => {
        console.log(this.s)
    }
}

let a = new A

a.f() // -> this is fine

let f1 = (new A).f
f1() // -> this is fine

Итак, это ошибка или особенность дизайна? Как TypeScript определяет тип this на самом деле?

Ответы [ 2 ]

0 голосов
/ 17 сентября 2018

Отличный вопрос. У Typescript есть то, что мы называем системой неправильных типов. (У Closure Compiler и Flow также есть некорректные системы типов.) Неполноценная система типов означает, что Typescript иногда вычисляет тип для выражения, которое является неправильным; он отличается от типа, который будет принимать выражение во время выполнения. Как упоминалось в другом ответе, это происходит потому, что JavaScript очень динамичен, и разработчики систем типов используют несколько быстрых клавиш, чтобы укротить сложность.

В вашем конкретном примере, хотя this может действительно any, на практике это почти всегда A, так что именно это выбирает Typescript. Тем не менее, он может потенциально предупредить на f1(), потому что метод вызывается как функция (т.е. без this).

0 голосов
/ 09 сентября 2018

Так что, по моему мнению, предполагаемый тип этого внутри f () должен быть следующим: любой, не этот: this.

ну да. В некотором смысле вы правы. Не на 100% уверен, что this внутри функции класса действительно является экземпляром класса. Но машинопись не должна быть точной на 100% ! Это важно понимать! Гарантии типа сохраняются не во всех ситуациях. Они буквально не могут.

Javascript очень динамический. Невозможно просто проанализировать всю эту динамику во время компиляции.

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

Просто никогда не делай этого:

const x = foo.x;
x();

на самом деле это приводит к тому, что более старые модели классов, чем классы ES6, такие как объектная модель ember, очень трудно использовать с машинописью - предположения просто не поддерживаются. И даже у лучших типографий есть ограничения. В JS есть вещи, которые вы не можете определить в TS. Тем не менее, TS может быть очень полезным для всех остальных случаев.

...