Spec-Zone.ru › TypeScript 5.1

Проверка типов JavaScript-файлов

Ниже приведены некоторые заметные отличия в работе проверки в файлах .js по сравнению с файлами .ts.

Свойства выводятся из присваиваний в телах классов

ES2015 не предоставляет способ объявления свойств в классах. Свойства динамически присваиваются, как и в объектных литералах.

В файле .js компилятор выводит свойства из присваиваний свойств внутри тела класса. Тип свойства — это тип, заданный в конструкторе, если он не определен или тип в конструкторе — undefined или null. В этом случае тип — это объединение типов всех правых частей в этих присваиваниях. Свойства, определенные в конструкторе, всегда предполагаются существующими, в то время как свойства, определенные только в методах, геттерах или сеттерах, считаются необязательными.

class C {
  constructor() {
    this.constructorOnly = 0;
    this.constructorUnknown = undefined;
  }
  method() {
    this.constructorOnly = false;
    this.constructorUnknown = "plunkbat"; // ok, constructorUnknown is string | undefined
    this.methodOnly = "ok"; // ok, but methodOnly could also be undefined
  }
  method2() {
    this.methodOnly = true; // also, ok, methodOnly's type is string | boolean | undefined
  }
}

Если свойства никогда не устанавливаются в теле класса, они считаются неизвестными. Если ваш класс имеет свойства, которые только считываются, добавьте и затем анотируйте объявление в конструкторе с помощью JSDoc, чтобы указать тип. Вам даже не нужно указывать значение, если оно будет инициализировано позже:

class C {
  constructor() {
    /** @type {number | undefined} */
    this.prop = undefined;
    /** @type {number | undefined} */
    this.count;
  }
}
 
let c = new C();
c.prop = 0; // OK
c.count = "string";

Функции-конструкторы эквивалентны классам

До ES2015 в JavaScript использовались функции-конструкторы вместо классов. Компилятор поддерживает этот шаблон и понимает функции-конструкторы как эквивалентные классам ES2015. Правила вывода свойств, описанные выше, работают точно так же.

function C() {
  this.constructorOnly = 0;
  this.constructorUnknown = undefined;
}
C.prototype.method = function () {
  this.constructorOnly = false;
  this.constructorUnknown = "plunkbat"; // OK, the type is string | undefined
};

Поддерживаются модули CommonJS

В файле .js TypeScript понимает формат модулей CommonJS. Присваивания exports и module.exports распознаются как объявления экспорта. Аналогично, вызовы функций require распознаются как импорты модулей. Например:

// same as `import module "fs"`
const fs = require("fs");

// same as `export function readFile`
module.exports.readFile = function (f) {
  return fs.readFileSync(f);
};

Поддержка модулей в JavaScript гораздо более синтаксически гибкая, чем поддержка модулей в TypeScript. Большинство комбинаций присваиваний и объявлений поддерживаются.

Классы, функции и объектные литералы — пространства имен

Классы являются пространствами имен в файлах .js. Это можно использовать для вложенных классов, например:

class C {}
C.D = class {};

И, для кода до ES2015, это можно использовать для имитации статических методов:

function Outer() {
  this.y = 2;
}
 
Outer.Inner = function () {
  this.yy = 2;
};
 
Outer.Inner();

Также это можно использовать для создания простых пространств имен:

var ns = {};
ns.C = class {};
ns.func = function () {};
 
ns;

Разрешены и другие варианты:

// IIFE
var ns = (function (n) {
  return n || {};
})();
ns.CONST = 1;
 
// defaulting to global
var assign =
  assign ||
  function () {
    // code goes here
  };
assign.extra = 1;

Объектные литералы открыты

В файле .ts объектный литерал, инициализирующий объявление переменной, присваивает его тип объявлению. Нельзя добавлять новые члены, которые не были указаны в исходном литерале. Это правило ослаблено в файле .js; объектные литералы имеют открытый тип (подпись индекса), позволяющий добавлять и искать свойства, которые не были определены изначально. Например:

var obj = { a: 1 };
obj.b = 2; // Allowed

Объектные литералы ведут себя так, как будто у них есть подпись индекса [x:string]: any, что позволяет рассматривать их как открытые карты вместо закрытых объектов.

Как и другие специальные поведения JS-проверки, это поведение можно изменить, указав тип JSDoc для переменной. Например:

/** @type {{a: number}} */
var obj = { a: 1 };
obj.b = 2;

null, undefined и пустые массивы инициализаторы имеют тип any или any[]

Любая переменная, параметр или свойство, инициализированное с помощью null или undefined, будет иметь тип any, даже если включены строгие проверки null. Любая переменная, параметр или свойство, инициализированное с помощью [], будет иметь тип any[], даже если включены строгие проверки null. Исключением являются свойства, которые имеют несколько инициализаторов, как описано выше.

function Foo(i = null) {
  if (!i) i = 1;
  var j = undefined;
  j = 2;
  this.l = [];
}
 
var foo = new Foo();
foo.l.push(foo.i);
foo.l.push("end");

Параметры функций по умолчанию являются необязательными

Поскольку в пре-ES2015 JavaScript нет способа указать необязательность параметров, все параметры функций в файле .js считаются необязательными. Допускаются вызовы с меньшим количеством аргументов, чем указано в объявлении параметров.

Важно отметить, что вызов функции с слишком большим количеством аргументов является ошибкой.

Например:

function bar(a, b) {
  console.log(a + " " + b);
}
 
bar(1); // OK, second argument considered optional
bar(1, 2);
bar(1, 2, 3); // Error, too many arguments

Функции, анотированные JSDoc, исключаются из этого правила. Используйте синтаксис необязательного параметра JSDoc ([ ]) для выражения необязательности. Например:

/**
 * @param {string} [somebody] - Somebody's name.
 */
function sayHello(somebody) {
  if (!somebody) {
    somebody = "John Doe";
  }
  console.log("Hello " + somebody);
}
 
sayHello();

Объявление параметра var-args, выведенное из использования arguments

Функция, тело которой содержит ссылку на ссылку arguments, неявно считается имеющей параметр var-arg (т.е. (...arg: any[]) => any). Используйте синтаксис var-arg JSDoc для указания типа аргументов.

/** @param {...number} args */
function sum(/* numbers */) {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

Неуказанные параметры типа по умолчанию any

Поскольку в JavaScript нет естественного синтаксиса для указания параметров типа дженериков, неуказанный параметр типа по умолчанию имеет значение any.

В предложении extends

Например, React.Component определено с двумя параметрами типа, Props и State. В файле .js нет законного способа указать их в предложении extends. По умолчанию аргументы типа будут any:

import { Component } from "react";

class MyComponent extends Component {
  render() {
    this.props.b; // Allowed, since this.props is of type any
  }
}

Используйте JSDoc @augments для явного указания типов. например:

import { Component } from "react";

/**
 * @augments {Component<{a: number}, State>}
 */
class MyComponent extends Component {
  render() {
    this.props.b; // Error: b does not exist on {a:number}
  }
}

В ссылках JSDoc

Неуказанный аргумент типа в JSDoc по умолчанию any:

/** @type{Array} */
var x = [];
 
x.push(1); // OK
x.push("string"); // OK, x is of type Array<any>
 
/** @type{Array.<number>} */
var y = [];
 
y.push(1); // OK
y.push("string"); // Error, string is not assignable to number

В вызовах функций

Вызов функции дженерика использует аргументы для вывода параметров типа. Иногда этот процесс не может вывести никакие типы, главным образом из-за отсутствия источников вывода; в этих случаях параметры типа будут по умолчанию any. Например:

var p = new Promise((resolve, reject) => {
  reject();
});

p; // Promise<any>;

Чтобы узнать обо всех функциях, доступных в JSDoc, см. ссылку.

© 2012-2024 Microsoft
Licensed under the Apache License, Version 2.0.
https://www.typescriptlang.org/docs/handbook/type-checking-javascript-files.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API