TypeScript 2.3 및 이후 버전에서는 –checkJs를 사용하여 .js 파일에서 타입 검사 및 오류 보고 모드를 지원합니다.
일부 파일에 // @ts-nocheck 주석을 추가하여 검사하는 것을 건너뛸 수 있습니다.
반대로 –checkJs를 설정하지 않고 // @ts-check 주석을 추가하여 몇개의 .js 파일 만 검사하도록 선택할 수 있습니다.
앞 줄에 // @ts-ignore를 추가하여 특정 라인의 오류를 무시할 수도 있습니다.
다음은 .ts 파일에서 .js 파일로 작업하는 방법에 주목할만한 차이점입니다:
흔히 .js 파일에서 .ts 파일처럼 타입을 추론할 수 있습니다.
마찬가지로 타입을 추론할 수 없는 경우 타입 주석을 .ts 파일에서와 같은 방식으로 JSDoc을 사용하여 지정할 수 있습니다.
Typescript처럼, –noImplicitAny는 컴파일러가 타입을 추론 할 수 없는 장소에 에러를 줄 것입니다. (무제한 객체 리터럴을 제외하고, 자세한 내용은 아래를 참조하십시오.)
JSDoc 주석은 선언을 추가하여 해당 선언의 타입을 설정하는 데 사용됩니다. 예를 들어:
/** @type {number} */ var x; x = 0; // 좋아요 x = false; // 오류: number에 boolean을 할당할 수 없습니다
JavaScript 문서에서 JSDoc 지원에서 지원되는 JSDoc 패턴의 전체 목록을 찾을 수 있습니다.
ES2015/ES6는 클래스에 속성을 선언하는 수단이 없습니다. 프로퍼티는 객체 리터럴처럼 동적으로 할당됩니다.
.js 파일에서 프로퍼티 선언은 클래스 본문 내부의 프로퍼티에 대한 할당에서 유추됩니다.
프로퍼티의 타입은 정의되지 않았거나 생성자의 타입이 정의되지 않았거나 널(null)인 경우를 제외하고 생성자에서 제공된 타입입니다.
이 경우 타입은 이러한 할당에서 모든 오른쪽 값의 타입을 결합한 것입니다.
생성자에 정의된 프로퍼티는 항상 존재한다고 가정되는 반면, 메서드, getter 또는 setter에 정의된 프로퍼티는 선택적으로 간주합니다.
class C { constructor() { this.constructorOnly = 0 this.constructorUnknown = undefined } method() { this.constructorOnly = false // error, constructorOnly is a number 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; } } let c = new C(); c.prop = 0; // 좋아요 c.prop = "string"; // 오류: number|undefined에 string을 할당할 수 없습니다
ES2015 이전에는 Javascript가 클래스 대신 생성자 함수를 사용했습니다. 컴파일러는 이 패턴을 지원하며 ES2015 클래스와 동일한 것으로 생성자 함수를 이해합니다. 위에서 설명한 속성 추론 규칙은 똑같은 방식으로 작동합니다.
function C() { this.constructorOnly = 0 this.constructorUnknown = undefined } C.prototype.method = function() { this.constructorOnly = false // error this.constructorUnknown = "plunkbat" // OK, the type is string | undefined }
.js 파일에서 Typescript는 CommonJS 모듈 형식을 인식합니다. 내보내기 및 module.exports에 대한 할당은 내보내기 선언으로 인식됩니다. 마찬가지로 require 함수 호출은 모듈 import로 인식됩니다. 예 :
// 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의 모듈 지원보다 훨씬 구문적으로 용감합니다. 할당과 선언의 대부분의 조합이 지원됩니다.
Classes는 .js파일에서 namespaces다. 이것은 중첩 클래스에 사용할 수 있다.
class C { } C.D = class { }
그리고, ES2015이전코드에 대해서, 이것은 정적 메서드를 시뮬레이트하는 데 사용할 수 있다.
function Outer() { this.y = 2 } Outer.Inner = function() { this.yy = 2 }
또한 간단한 네임스페이스를 만드는 데에도 사용할 수 있습니다.
var ns = {} ns.C = class { } ns.func = function() { }
다른 변형도 허용됩니다.
// 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 파일에서 완화됩니다. 객체 리터럴은 원래 정의되지 않은 속성을 추가 및 검색 할 수있는 개방형 타입 (색인 서명)을 가지고 있습니다. 예를 들면 :
객체 리터럴에는 제한이 없습니다 기본적으로 변수 선언에 객체 리터럴은 선언의 타입을 제공합니다. 원래 초기화 시에는 지정되지 않은 새 멤버를 추가할 수 없습니다. 이 규칙은 .js 파일에서 관대한 편입니다. 객체 리터럴은 원래 정의되지 않은 속성을 추가하고 조회할 수 있는 확장 가능한(open-ended) 타입을 가지고 있습니다.
예를 들어:
var obj = { a: 1 }; obj.b = 2; // 허용됨
객체 리터럴은 닫힌 객체가 아닌 오픈 maps으로 처리될 수 있도록 하는 기본 인덱스 시그니처 [x:string]: any을 갖습니다.
다른 특별한 JS 검사와 마찬가지로, 이 동작은 변수에 대한 JSDoc 타입을 지정하여 변경할 수 있습니다.
예를 들어:
/** @type {{a: number}} */ var obj = { a: 1 }; obj.b = 2; // 오류, {a: number} 타입은 b 프로퍼티를 가지고 있지 않습니다.
엄격한 널 (null) 검사가 설정된 경우에도 널 또는 undefined로 초기화되는 모든 변수, 매개 변수 또는 특성의 타입은 any입니다. 엄격한 널 검사가 설정되어 있어도 []로 초기화 된 변수, 매개 변수 또는 특성은 any[] 타입을 갖습니다. 유일한 예외는 위에서 설명한 여러 초기화 프로그램이있는 속성입니다.
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");
JS에서 매개 변수를 선택적으로 지정할 방법이 없기때문에(기본값을 지정하지 않고).js 파일의 모든 함수 매개 변수는 선택사항으로 간주합니다. 소수의 인수 호출은 허용됩니다.
인수가 너무 많은 함수를 호출하는 것은 오류라는 점을 주목하는 것이 중요합니다.
예를 들어:
function bar(a, b){ console.log(a + " " + b); } bar(1); // 좋아요, 두번째 인수는 선택사항으로 간주됩니다 bar(1, 2); bar(1, 2, 3); // 오류, 인수가 너무 많습니다
JSDoc 주석이 적용된 함수는 이 규칙에서 제외됩니다. 선택사항을 명시하기 위해 JSDoc 선택적 매개 변수 구문을 사용하세요.
예:
/** * @param {string} [somebody] - Somebody의 이름 */ function sayHello(somebody) { if (!somebody) { somebody = 'John Doe'; } alert('Hello ' + somebody); } sayHello();
본문이 arguments 참조에 대한 참조를 갖는 함수는 var-arg 매개변수 (즉, (…arg: any[]) ⇒ any)가 있음을 암시적으로 간주합니다.
JSDoc var-arg 구문을 사용하여 인수의 타입을 지정하세요.
/** @param {...number} args */ function sum(/* numbers */) { var total = 0 for (var i = 0; i < arguments.length; i++) { total += arguments[i] } return total }
지정되지 않은 제네릭 타입 매개변수는 기본적으로 any로 설정됩니다. 이런 일이 발생하는 곳은 거의 없습니다:
예를 들어, React.Component는 Props와 State의 두 가지 제네릭 타입 매개 변수를 갖도록 정의됩니다. .js파일에는 extend 절에 이들을 지정하는 합법적 인 방법이 없습니다..js` 파일에는 extend에 이것들을 지정하는 정당한 방법이 없습니다.
기본적으로 타입 인수는 any입니다:
import { Component } from "react"; class MyComponent extends Component { render() { this.props.b; // 허용됨, this.props는 any 타입이므로 } }
JSDoc@augments를 사용하여 사용하여 타입을 명시적으로 지정합니다.
예:
import { Component } from "react"; /** * @augments {Component<{a: number}, State>} */ class MyComponent extends Component { render() { this.props.b; // 오류: b는 {a:number}에 존재하지 않습니다 } }
JSDoc의 지정되지 않은 제네릭 타입 인수의 기본값은 any입니다.
/** @type{Array} */ var x = []; x.push(1); // 좋아요 x.push("string"); // 좋아요, x는 Array<any>의 타입입니다 /** @type{Array.<number>} */ var y = []; y.push(1); // 좋아요 y.push("string"); // 오류, string은 number에 할당할 수 없습니다
제네릭 함수 호출은 제네릭 타입 매개 변수를 추론하기 위한 인수를 사용합니다. 때때로 이 프로세스는 추론 소스가 부족하여 어떤 타입도 추론하지 못하는 경우가 있습니다. 이 경우 제네릭 타입 매개 변수는 any로 기본 설정됩니다.
예를 들어:
var p = new Promise((resolve, reject) => { reject() }); p; // Promise<any>;
아래 목록은 JSDoc 주석을 사용하여 JavaScript 파일에 유형 정보를 제공 할 때 현재 지원되는 구문을 요약합니다.
아래 명시 적으로 나열되지 않은 태그 (예 : @async)는 아직 지원되지 않습니다.
의미는 일반적으로 usejsdoc.org에서 제공되는 태그의 의미와 동일하거나 상위 집합입니다. 아래 코드는 차이점을 설명하고 각 태그의 사용 예를 보여줍니다.
“@type”태그를 사용하고 유형 이름 (TypeScript 선언에 정의 된 프리미티브 또는 JSDoc “@typedef”태그) 을 참조 할 수 있습니다. 모든 Typescript 유형과 대부분의 JSDoc 유형을 사용할 수 있습니다.
/** * @type {string} */ var s; /** @type {Window} */ var win; /** @type {PromiseLike<string>} */ var promisedString; // You can specify an HTML Element with DOM properties /** @type {HTMLElement} */ var myElement = document.querySelector(selector); element.dataset.myData = '';
@type 공용체 타입를 기술가능하다. — for example, something can be either a string or a boolean.
/** * @type {(string | boolean)} */ var sb;
괄호는 공용체 타입의 경우 선택 사항입니다.
/** * @type {string | boolean} */ var sb;
다양한 구문을 사용하여 배열 유형을 지정할 수 있습니다.
/** @type {number[]} */ var ns; /** @type {Array.<number>} */ var nds; /** @type {Array<number>} */ var nas;
객체 리터럴 유형을 지정할 수도 있습니다. 예를 들어 'a'(문자열) 및 'b'(숫자) 속성을 가진 객체는 다음 구문을 사용합니다.
/** @type {{ a: string, b: number }} */ var var9;
표준 JSDoc 구문 또는 Typescript 구문을 사용하여 문자열 및 숫자 인덱스 시그니처를 사용하여 맵과 같은 객체 및 배열과 같은 객체를 지정할 수 있습니다.
/** * A map-like object that maps arbitrary `string` properties to `number`s. * * @type {Object.<string, number>} */ var stringToNumber; /** @type {Object.<number, object>} */ var arrayLike;
앞의 두 유형은 Typescript 유형 { {x : string} : number} 및 {[x : number] : any}와 같습니다. 컴파일러는 두 구문을 모두 이해합니다.
Typescript 또는 Closure 구문을 사용하여 함수 유형을 지정할 수 있습니다.
/** @type {function(string, boolean): number} Closure syntax */ var sbn; /** @type {(s: string, b: boolean) => number} Typescript syntax */ var sbn2;
또는 알 수없는 함수 유형을 사용할 수 있습니다.
/** @type {Function} */ var fn7; /** @type {function} */ var fn6;
Closure의 다른 유형도 사용할 수 있습니다.
/** * @type {*} - can be 'any' type */ var star; /** * @type {?} - unknown type (same as 'any') */ var question;
Typescript는 Closure의 캐스트 구문을 사용합니다. 이렇게하면 괄호 안에있는 표현식 앞에 @type 태그를 추가하여 유형을 다른 유형으로 변환 할 수 있습니다.
/** * @type {number | string} */ var numberOrString = Math.random() < 0.5 ? "hello" : 100; var typeAssertedNumber = /** @type {number} */ (numberOrString)
가져 오기 유형을 사용하여 다른 파일에서 선언을 가져올 수도 있습니다. 이 구문은 Typescript에 고유하며 JSDoc 표준과 다릅니다.
/** * @param p { import("./a").Pet } */ function walk(p) { console.log(`Walking ${p.name}...`); }
import types can also be used in type alias declarations:
/** * @typedef { import("./a").Pet } Pet */ /** * @type {Pet} */ var myPet; myPet.name;
import types can be used to get the type of a value from a module if you don’t know the type, or if it has a large type that is annoying to type:
/** * @type {typeof import("./a").x } */ var x = require("./a").x;
@param uses the same type syntax as @type, but adds a parameter name. The parameter may also be declared optional by surrounding the name with square brackets:
// Parameters may be declared in a variety of syntactic forms /** * @param {string} p1 - A string param. * @param {string=} p2 - An optional param (Closure syntax) * @param {string} [p3] - Another optional param (JSDoc syntax). * @param {string} [p4="test"] - An optional param with a default value * @return {string} This is the result */ function stringsStringStrings(p1, p2, p3, p4){ // TODO }
Likewise, for the return type of a function:
/** * @return {PromiseLike<string>} */ function ps(){} /** * @returns {{ a: string, b: number }} - May use '@returns' as well as '@return' */ function ab(){}
@typedef may be used to define complex types. Similar syntax works with @param.
/** * @typedef {Object} SpecialType - creates a new type named 'SpecialType' * @property {string} prop1 - a string property of SpecialType * @property {number} prop2 - a number property of SpecialType * @property {number=} prop3 - an optional number property of SpecialType * @prop {number} [prop4] - an optional number property of SpecialType * @prop {number} [prop5=42] - an optional number property of SpecialType with default */ /** @type {SpecialType} */ var specialTypeObject;
You can use either object or Object on the first line.
/** * @typedef {object} SpecialType1 - creates a new type named 'SpecialType1' * @property {string} prop1 - a string property of SpecialType1 * @property {number} prop2 - a number property of SpecialType1 * @property {number=} prop3 - an optional number property of SpecialType1 */ /** @type {SpecialType1} */ var specialTypeObject1;
@param allows a similar syntax for one-off type specifications. Note that the nested property names must be prefixed with the name of the parameter:
/** * @param {Object} options - The shape is the same as SpecialType above * @param {string} options.prop1 * @param {number} options.prop2 * @param {number=} options.prop3 * @param {number} [options.prop4] * @param {number} [options.prop5=42] */ function special(options) { return (options.prop4 || 1001) + options.prop5; }
@callback is similar to @typedef, but it specifies a function type instead of an object type:
/** * @callback Predicate * @param {string} data * @param {number} [index] * @returns {boolean} */ /** @type {Predicate} */ const ok = s => !(s.length % 2);
Of course, any of these types can be declared using Typescript syntax in a single-line @typedef:
/** @typedef {{ prop1: string, prop2: string, prop3?: number }} SpecialType */ /** @typedef {(data: string, index?: number) => boolean} Predicate */
You can declare generic types with the @template tag:
/** * @template T * @param {T} x - A generic parameter that flows through to the return type * @return {T} */ function id(x){ return x }
Use comma or multiple tags to declare multiple type parameters:
/**
* @template T,U,V
* @template W,X
*/
You can also specify a type constraint before the type parameter name. Only the first type parameter in a list is constrained:
/** * @template {string} K - K must be a string or string literal * @template {{ serious(): string }} Seriousalizable - must have a serious method * @param {K} key * @param {Seriousalizable} object */ function seriousalize(key, object) { // ???? }
The compiler infers constructor functions based on this-property assignments, but you can make checking stricter and suggestions better if you add a @constructor tag:
/** * @constructor * @param {number} data */ function C(data) { this.size = 0; this.initialize(data); // Should error, initializer expects a string } /** * @param {string} s */ C.prototype.initialize = function (s) { this.size = s.length } var c = new C(0); var result = C(1); // C should only be called with new
With @constructor, this is checked inside the constructor function C, so you will get suggestions for the initialize method and an error if you pass it a number. You will also get an error if you call C instead of constructing it.
Unfortunately, this means that constructor functions that are also callable cannot use @constructor.
The compiler can usually figure out the type of this when it has some context to work with. When it doesn’t, you can explicitly specify the type of this with @this:
/** * @this {HTMLElement} * @param {*} e */ function callbackForLater(e) { this.clientHeight = parseInt(e) // should be fine! }
When Javascript classes extend a generic base class, there is nowhere to specify what the type parameter should be. The @extends tag provides a place for that type parameter:
/** * @template T * @extends {Set<T>} */ class SortableSet extends Set { // ... }
Note that @extends only works with classes. Currently, there is no way for a constructor function extend a class.
The @enum tag allows you to create an object literal whose members are all of a specified type. Unlike most object literals in Javascript, it does not allow other members.
/** @enum {number} */ const JSDocState = { BeginningOfLine: 0, SawAsterisk: 1, SavingComments: 2, }
Note that @enum is quite different from, and much simpler than, Typescript’s enum. However, unlike Typescript’s enums, @enum can have any type:
/** @enum {function(number): number} */ const Math = { add1: n => n + 1, id: n => -n, sub1: n => n - 1, }
var someObj = { /** * @param {string} param1 - Docs on property assignments work */ x: function(param1){} }; /** * As do docs on variable assignments * @return {Window} */ let someFunc = function(){}; /** * And class methods * @param {string} greeting The greeting to use */ Foo.prototype.sayHi = (greeting) => console.log("Hi!"); /** * And arrow functions expressions * @param {number} x - A multiplier */ let myArrow = x => x * x; /** * Which means it works for stateless function components in JSX too * @param {{a: string, b: number}} test - Some param */ var fc = (test) => <div>{test.a.charAt(0)}</div>; /** * A parameter can be a class constructor, using Closure syntax. * * @param {{new(...args: any[]): object}} C - The class to register */ function registerClass(C) {} /** * @param {...string} p1 - A 'rest' arg (array) of strings. (treated as 'any') */ function fn10(p1){} /** * @param {...string} p1 - A 'rest' arg (array) of strings. (treated as 'any') */ function fn9(p1) { return p1.join(); }
Referring to objects in the value space as types doesn’t work unless the object also creates a type, like a constructor function.
function aNormalFunction() { } /** * @type {aNormalFunction} */ var wrong; /** * Use 'typeof' instead: * @type {typeof aNormalFunction} */ var right;
Postfix equals on a property type in an object literal type doesn’t specify an optional property:
/** * @type {{ a: string, b: number= }} */ var wrong; /** * Use postfix question on the property name instead: * @type {{ a: string, b?: number }} */ var right;
Nullable types only have meaning if strictNullChecks is on:
/** * @type {?number} * With strictNullChecks: true -- number | null * With strictNullChecks: off -- number */ var nullable;
Non-nullable types have no meaning and are treated just as their original type:
/** * @type {!number} * Just has type number */ var normal;
Unlike JSDoc’s type system, Typescript only allows you to mark types as containing null or not. There is no explicit non-nullability – if strictNullChecks is on, then number is not nullable. If it is off, then number is nullable.