TypeScript Notes
# TypeScript Study Notes
TypeScript's type checking is for the programmer's benefit; it does not exist in the compiled output.
# Type Annotations
function fn(person: string):void{ // Parameter type is string, no return value
///...
}
fn('str') // If a non-string argument is passed, the VS Code editor or the compiler will show an error
const test:number = 1
2
3
4
5
6
# What Are the Basic Type Annotations?
// Primitive types
:string
:number
:boolean
:null // can only be null
:undefined // can only be undefined
:symbol
// Reference types
:object // not commonly used; interfaces are more often used for object type annotations
// Other
:any // any type
:void // empty, used for functions with no return value
:never // used for functions whose code never finishes executing (e.g., functions that throw errors, infinite loops)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# What Are Type Annotations, Type Inference, and Type Assertions?
Type annotation is explicitly specifying the type.
Type inference is when the editor automatically infers the type from the value (hover over a variable in the editor to see the type hint).
Type assertion tells the compiler, "Trust me, it is this type."
// Type annotation is explicitly writing the type
const myNumber: number = 123
// Type inference infers the type from the value (hover over a variable to see the type or value hint)
const myString = 'test'
// Type assertion (the developer knows exactly what the type is)
const someValue:any = 'abc'
const strLength:number = (someValue as string).length // Assert that someValue is of type string
2
3
4
5
6
7
8
9
# Type Assertions
const el = document.querySelector('#img');
(el as HTMLImageElement).src = 'xx' // Assert that el is an HTMLImageElement
// Type assertion inside an object
type TestObj = {
a: string
};
const obj = {
test: <TestObj>{
a: 'aaa'
}
}
// Or
const obj = {
test: {
a: 'aaa'
} as TestObj ,
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Object Types
// Object literal type checking
const xiaojiejie: {
name: string,
age: number
} = {
name: 'Xiaohong',
age: 18
}
// Annotating with :object
const obj:object = {}
// Using interfaces
interface Person{
name: string
age: number
}
const xjj: Person = {
name: 'xh',
age: 18
}
// Class type checking
class Parson { }
const xiaobai: Parson = new Parson()
// Function and return value type checking
const fn: ()=> string = () => '123'
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Function Type Annotations
// Function return value type annotation: fn(): number {}
function getTotal2(one: number, two: number): number {
return one + two
}
getTotal2(1,2)
// No return value: void
function sayHello(): void {
console.log("Hello")
}
// Function that never finishes executing
function setTimer():never {
throw new Error()
console.log(123)
}
// Annotation when the parameter is an object (interfaces can also be used)
function add({ one, two }: {one: number, two: number}) {
return one + two
}
const total = add({one: 1, two: 2})
// Defining function types with type aliases
type Callback = (a: string) => string
let fn: Callback = (a) => ''
// Defining function types with interfaces
interface ICallBack {
(a: string): string
}
let fn1: ICallBack = (a) => ''
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# this Types in Functions
interface TestObj {
a: number,
fn: (x: number) => void
}
// this in regular functions
let obj: TestObj = {
a: 1,
fn(this: TestObj, x: number){ // Note: this here is not a parameter, it's just a type annotation for this. x is still the first parameter
this.a
}
}
// this in arrow functions (this is fixed to the scope where the function is declared)
let obj2: TestObj = {
a: 1,
fn(this: TestObj, x: number) {
return () => {
this.a
}
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# Function Overloading (parameter combination contracts)
Native JS doesn't have true function overloading -- functions with the same name get overwritten. But TypeScript supports it.
A Brief Discussion on JavaScript Function Overloading (opens new window)
TS supports function overloading, generally used for defining type contracts between different parameters/parameter counts and return values.
// First contract (when attr is 'display', value must be 'block' | 'nonde')
function showOrHide(ele: HTMLElement, attr: 'display', value: 'block' | 'nonde');
// Second contract (when attr is 'opacity', value must be number)
function showOrHide(ele: HTMLElement, attr: 'opacity', value: number);
// Function implementation
function showOrHide(ele: HTMLElement, attr: any, value: any) {
// ...
}
// Interfaces can also declare function overloads
interface Fn{
(name: string): string
(name: number): number
}
const fn: Fn= () =>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
More on TS function overloading (opens new window)
# Array Type Annotations
const numberArr: number[] = [1, 2, 3]
const stringArr: string[] = ['a', 'b']
const undefinedArr: undefined[] = [undefined, undefined]
const arr: (number | string | boolean)[] = [1, 'a', true, false] // Using union types
// Type alias
type lady = { name: string, age: number }
const xiaojj: lady[] = [
{
name: 'xiaojj',
age: 90
},
{
name: 'j',
age: 30
}
]
// Or using a class
class Ady2 {
name: string;
age: number;
}
const xiaojj2: Ady2[] = [
{
name: 'xiaojj',
age: 90
},
{
name: 'j',
age: 30
}
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# Tuples
A tuple can be understood as: an array with a known number of elements and known types
// Union types
const xjj:(string | number)[] = ['a',22,'b'] // The entire array can contain string or number
// Tuple annotation (note: only a single pair of brackets here)
const xjj1: [string, number, number] = ['a', 22, 33] // Specifies the type at each position in the array
// Note: Tuples are used relatively rarely in development
// CSV-style data format definition; (2D arrays need an extra pair of brackets)
const xjj2: [string, number, number][] = [
['a', 22, 33],
['a', 22, 33]
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Interfaces
An interface can be understood as a type description of an object's properties. Similar to type aliases, the difference is that an interface must be an object, while an alias can directly be a type, e.g., type Girl = string
interface Girl { // Interface (think: type description of object properties)
readonly name: string; // Readonly property (cannot be modified after definition)
age: number;
waistline?: number; // Adding ? makes it optional
[propname: string]: any; // Allows unlimited properties with string keys and any values
say(): string; // Function type, returns string (use void when no return value). say() can also include parameter type checking, e.g., say(p:number)
}
// Similar to type aliases, the difference is that an interface must be an object, while an alias can directly be a type, e.g., type Girl = string
// Interface inheritance
interface Teacher extends Girl {
teach(): string;
}
const girl = {
name: 'Dajiao',
age: 18,
sex: 'female',
say() {
return 'Welcome'
},
teach() {
return 'teach'
}
}
const screenResume = ({ name, age, bust, sex }: Girl) => {
console.log(name, age, bust, sex)
}
const getResume = ({ name, age, bust, teach}: Teacher) => {
teach();
console.log(name, age, bust)
}
screenResume(girl)
getResume(girl)
// Using interfaces in classes
class xiaojjj implements Girl {
name = "xiaojj"
age = 18
bust = 98
sex = 'female'
say() {
return 'Welcome'
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Indexable Types
interface Arr {
[index: number]:string // Accessing data by index returns a string type
}
const myArr:Arr = ['1','2','3']
const myStr:string = myArr[1]
2
3
4
5
6
# Applying TS in ES6 Classes
# Class Modifiers
// Class modifiers:
// public -- accessible from both inside and outside the class
// protected -- accessible from inside the class and its subclasses
// private -- accessible only from inside the class, not from subclasses
// Inside and outside the class: {} is the inside, everything else is outside
class Person {
// public -- accessible from both inside and outside. Can be omitted; default is public. protected -- accessible only from inside
name: string // The string annotation here is for TS usage
private age: 18
public sayHello() {
console.log(this.name + this.age + 'say hello')
}
}
class Teacher2 extends Person {
public sayBye() {
console.log(this.name + ' say bye') // protected can be used within inheritance
}
}
const person = new Person();
person.name = 'test' // Defined outside the class
console.log(person.name)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Using Type Checking in Class Constructors
class Person2 {
constructor(public name: string) {
this.name = name
}
}
class Teacher3 extends Person2{
constructor(public age: number) {
super('test-name') // This value is passed to Person2's constructor. Even if the parent class has no constructor, the child class constructor must still call super()
}
}
const teacher3 = new Teacher3(18)
console.log(teacher3.name)
console.log(teacher3.age)
2
3
4
5
6
7
8
9
10
11
12
13
14
# Class Getters, Setters, and Static Members
class Xjj {
constructor(private _age: number) { }
get age() {
return this._age - 10;
} // Accessor property: accessed like a property, with the ability to wrap the value
set age(age: number) {
this._age = age+3;
}
}
const dj = new Xjj(28);
dj.age = 25
console.log(dj.age)
// Static property: a property that can be accessed directly via Girl.prop without instantiation
class Girl {
static sayLove() {
return 'I love you'
}
}
// const girl = new Girl()
console.log(Girl.sayLove())
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Readonly Properties in Classes
// Readonly properties
class Person {
public readonly _name: string // Readonly property
constructor(name: string) {
this._name = name;
}
}
const person = new Person('testName');
// person._name = '222'; // Cannot modify a readonly property
console.log(person._name)
2
3
4
5
6
7
8
9
10
11
# Abstract Classes
/ Abstract class
abstract class Girls {
abstract skill(); // Note: only defines the abstract method, no implementation
}
class Waiter extends Girls{ // After inheriting an abstract class, you must implement its abstract members
skill() {
console.log('Serve 1')
}
}
class BaseTeacher extends Girls{
skill() {
console.log('Serve 2')
}
}
class SeniorTeacher extends Girls{
skill() {
console.log('Serve 3')
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// The abstract keyword marks a class as abstract (no concrete implementation, cannot be instantiated with new. Subclasses inheriting this abstract class must implement the corresponding methods; used to standardize subclasses)
abstract class Component<T1, T2> {
props: T1;
state: T2;
constructor(props: T1) {
this.props = props
}
// Methods marked with abstract cannot have a concrete implementation
abstract render(): string
}
// Standardizing a class's props and state
interface Props {
val: number
}
interface State {
x: number
}
// Standardizing methods within the class
interface Log {
getInfo(): string
}
interface Save {
save(): void
}
// <Props, State> passes types via generics. The implements keyword requires the current class to fulfill the contracts defined in the Log and Save interfaces
class MyComponent extends Component<Props, State> implements Log, Save {
constructor(props: Props) {
super(props)
this.state = {
x: 1
}
}
render() {
// this.props.val
// this.state.x
return '<MyComponent>'
}
getInfo(): string {
return ''
}
save() {
}
}
const myComponent = new MyComponent({ val: 1 })
myComponent.render()
/**
* Using interfaces in classes with the implements keyword:
* 1. If a class implements an interface, it must fulfill the contracts defined in that interface
* 2. Multiple interfaces are separated by commas
* 3. implements and extends can coexist
*/
/**
* TS class and interface key points:
* 1. Abstract classes produce actual code after compilation; interfaces do not
* 2. TS only supports single inheritance; a subclass can only have one parent class
* 3. Interfaces cannot have implementations; abstract classes can have property implementations but no method implementations
*/
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# Union Types and Type Guards
Union types means a parameter can be one of multiple types.
Type guards means performing operations only when the parameter is of a certain type.
interface Waiter {
anjiao: boolean
say: () => {}
}
interface Teacher {
anjiao: boolean
skill: () => {}
}
function judgeWho(animal: (Waiter | Teacher)) { // Union type
// First assertion method
if (animal.anjiao) {
// (animal as Teacher) means: assert that animal is of type Teacher
(animal as Teacher).skill()
} else {
(animal as Waiter).say()
}
// Second assertion method
if ('skill' in animal) {
animal.skill()
} else {
animal.say()
}
// Third type guard method uses typeof (code omitted)
}
class NumberObj {
count: number
}
function addObj(first: object | NumberObj, second: object | NumberObj) { // Union type
if (first instanceof NumberObj && second instanceof NumberObj) { // Type guard
return first.count + second.count;
}
return 0;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# Enums
// Enum type (Think of enums as: defining a set of optional constants. Using constant names to represent the meaning of values improves readability.)
// JS approach
// const Status = {
// MASSAGE: 0,
// SPA: 1,
// DABAOJIAN: 2
// }
// TS approach
enum Status {
MASSAGE, // To start from 1, set MASSAGE = 1
SPA,
DABAOJIAN
} // Default values: 0, 1, 2
console.log(Status.MASSAGE, Status[0]) // 0, MASSAGE Reverse lookup via index is possible
function getStatus(status: any) {
if (status === Status.MASSAGE) {
return 'massage'
} else if (status === Status.SPA) {
return 'spa'
} else if (status === Status.DABAOJIAN) {
return 'dabaojian'
}
}
const result = getStatus(Status.SPA)
console.log(result)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Generics
Generics can be understood simply as: a generic (non-specific) type. (Similar to formal and actual parameters in functions)
# Using Generics in Functions
// function join(first: string | number, second: string | number) {
// return `${first}${second}`
// }
// join('jspang', 1); // What if I want both parameters to be strings when the first is a string? That's where generics come in
// Using generics: like defining formal parameters, you specify the type when calling
function join<JSPang>(first: JSPang, second: JSPang) {
return `${first}${second}`
}
join<string>('jspang', '123');
join<number>(11, 22);
// Using arrays with generics
function myFun<ANY>(params:ANY[]) { // ANY[] or Array<ANY>
return params
}
myFun<string>(['a', 'b'])
// Using two type parameters (in practice, T is commonly used for generics)
function join2<T,P>(first: T, second: P) {
return `${first}${second}`
}
join2<string,number>('jspang', 123);
join2<number, string>(11, '22');
join2(11, '22'); // Generics also support type inference (hover over the function name for hints)
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# Using Generics in Classes
// class SelectGirl {
// constructor(private girls: string[] | number[]) { } // private: external code cannot modify
// getGirl(index: number): string | number {
// return this.girls[index]
// }
// }
// Using generics
class SelectGirl<T> { // Generic constraint: <T extends number | string>
constructor(private girls: T[]) { } // private: external code cannot modify
getGirl(index: number): T {
return this.girls[index]
}
}
// const selectGirl = new SelectGirl<string>(['Dajiao', 'xiaohong', 'xiaobai'])
const selectGirl = new SelectGirl<number>([101, 102, 103])
console.log(selectGirl.getGirl(1))
// Inheritance with generics
interface Girl {
name: string
}
class SelectGirl2<T extends Girl> { // Generic T must have a name property, inherited from the Girl interface
constructor(private girls: T[]) { } // private: external code cannot modify
getGirl(index: number): string {
return this.girls[index].name
}
}
const selectGirl2 = new SelectGirl2([
{name: 'Dajiao1'},
{name: 'Dajiao2'},
{name: 'Dajiao3'}
])
console.log(selectGirl2.getGirl(1))
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# Type Guards
In JavaScript, we commonly use conditional checks to handle logic. In TypeScript, these conditional blocks have an additional feature: narrowing the type range based on the check result (somewhat like assertions). This feature is called type guards. The triggering conditions are:
Logical conditional blocks: if, else, elseif
Specific keywords: typeof, instanceof, in
# typeof
function fn(a: string|number) {
// error: cannot guarantee a is a string
a.substring(1);
if (typeof a === 'string') {
// ok
a.substring(1);
} else {
// ok
a.toFixed(1);
}
}
2
3
4
5
6
7
8
9
10
11
# instanceof
function fn(a: Date|Array<any>) {
if (a instanceof Array) {
a.push(1);
} else {
a.getFullYear();
}
}
2
3
4
5
6
7
# in
interface IA {
x: string;
y: string; }
interface IB {
a: string;
b: string; }
function fn(arg: IA | IB) {
if ('x' in arg) {
// ok
arg.x;
// error
arg.a;
} else {
// ok
arg.a;
// error
Literal type guards
If the type is a literal type, you can also infer based on the literal value
Custom type guards
Sometimes the methods above cannot satisfy special cases, and you can define custom type guard rules
arg.x;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Literal Type Guards
interface IA {
type: 'IA';
x: string;
y: string;
}
interface IB {
type: 'IB';
a: string;
b: string;
}
function fn(arg: IA | IB) {
if (arg.type === 'IA') {
// ok
arg.x;
// error
arg.a;
} else {
// ok
arg.a;
// error
arg.x;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Custom Type Guards
function canEach(data: any): data is Element[]|NodeList {
return data.forEach !== undefined;
}
function fn2(elements: Element[]|NodeList|Element) {
if ( canEach(elements) ) {
elements.forEach((el: Element)=>{
el.classList.add('box');
});
} else {
elements.classList.add('box');
}
}
2
3
4
5
6
7
8
9
10
11
12
data is Element[]|NodeList is a type predicate, with the format: xx is XX. A function returning this type can be
recognized by TypeScript as a type guard.
# Type Operations
# typeof
Get the type of data
let str = 'kkk'
let t = typeof str // Use typeof to get the type of str, returns string to variable t (native JS typeof usage)
type myType = typeof str // Use typeof to get the type of str, returns string to type myType (TS typeof usage)
2
3
4
5
6
# keyof
Get the set of all keys of a type
// Usage example 1
interface Person{
name: string;
age: number;
}
type PersonKeys = keyof Person
// Equivalent to: type PersonKeys = 'name' | 'age'; // Note: a set of keys, not values
2
3
4
5
6
7
8
// Usage example 2
let p1 = {
name: 'xx',
age: 28
}
// The effect of keyof typeof p1: first typeof extracts the type of the p1 object, then keyof extracts the key set from the type, result: 'name' | 'age'
function getPersonVal(k: keyof typeof p1){
return p1[k]
}
2
3
4
5
6
7
8
9
10
# in
Internally uses for...in to iterate over a type
interface Person{
name: string;
age: number;
}
type PersonKeys = keyof Person; // 'name' | 'age'
type NewPerson = {
[k in PersonKeys]: string
// Can also be written as [k in 'name' | 'age']: string
// or [k in keyof Person]: string
} // {name: string; age: string;}
2
3
4
5
6
7
8
9
10
11
# Configuration File tsconfig.json
// This file is generated by the tsc -init command
// Running the tsc command directly will use this configuration file
// Option details: https://www.tslang.cn/docs/handbook/compiler-options.html
{
// "include": ["demo15-1.ts"], // Specific files to compile; without this, tsc compiles all by default
// "files": ["demo15-1.ts"], // Similar to include
// "exclude": ["demo15-3.ts"], // Specific files to exclude from compilation
"compilerOptions": { // Compiler options
/* Basic Options */
// "incremental": true, /* Enable incremental compilation */
"target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
// "lib": [], /* Specify library files to be included in the compilation. */
// "allowJs": true, /* Allow compiling JavaScript files */
// "checkJs": true, /* Report errors in .js files. */
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
// "declaration": true, /* Generate corresponding .d.ts files */
// "declarationMap": true, /* Generate a sourcemap for each corresponding .d.ts file (mapping compiled code to source) */
"sourceMap": true, /* Generate source file to output file mapping files (.map). */
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./build", /* Output JS file directory. */
"rootDir": "./src", /* TS source file directory. */
// "composite": true, /* Enable project compilation */
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
// "removeComments": true, /* Do not emit comments to output. (Deletes all comments, except copyright info starting with /!*.) */
// "noEmit": true, /* Do not emit outputs. */
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
// "isolatedModules": true, /* Treat each file as a separate module (similar to 'ts.transpileModule') */
/* Strict Type Checking Options */
"strict": true, /* Enable all strict type checking options. When enabled, the options below don't need to be set individually */
// "noImplicitAny": true, /* Raise errors on expressions and declarations with an implied 'any' type. (When false, allows implicit any without explicit declaration) */
// "strictNullChecks": true, /* Enable strict null checks. (When false, allows assigning null) */
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
// "noImplicitThis": true, /* Raise errors on 'this' expressions with an implied 'any' type. */
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
// "noUnusedLocals": true, /* Report errors on unused local variables */
// "noUnusedParameters": true, /* Report errors on unused parameters. */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statements. */
/* Module Resolution Options */
// "moduleResolution": "node", /* Determine how modules are resolved: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
// "baseUrl": "./", /* Base directory for resolving non-absolute module names. */
// "paths": {}, /* A list of path mappings based on baseUrl. */
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
// "typeRoots": [], /* List of folders to include type definitions from. */
// "types": [], /* Type declaration file names to include */
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"esModuleInterop": true /* Enable interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
/* Source Map Options */
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
/* Experimental Options */
// "experimentalDecorators": true, /* Enable experimental support for ES7 decorators. */
// "emitDecoratorMetadata": true, /* Enable experimental support for emitting type metadata for decorators. */
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70