Typescript项目注意点和基本类型介绍

从typescript源文件到执行的过程

执行者 步骤 说明
TSC 1. TypeScript Source -> TypeScript AST TSC将ts文件转为TS AST(abstract syntax tree)
TSC 2. AST is checked by typechecker TSC的类型检查器对AST做类型检查
TSC 3. TypeScript AST -> Javascript Source TSC将TS AST转为JS的源代码(可能是ES3/5/6)
JS(浏览器/Node.js) 4. Javascript Source -> Javascript AST JS运行时将JS源码转为JS AST
JS(浏览器/Node.js) 5. Javascript AST -> bytecode JS运行时将JS AST 转为字节码,准备运行
JS(浏览器/Node.js) 6. Bytecode is evaluated by runtime JS运行时运行js字节码

其中1-3步是TSC处理的,4-6步为JS运行时处理,可能是浏览器也可能是Node.js。

从上面步骤可以知道,TSC做类型检查是在将TS AST转为JS源码之前,也就是说从TS AST转为JS源码时,是没有做类型检查的。检查类型时针对TS AST的,即第二步。

也意味着TS的类型系统,强类型的各种机制,仅仅对类型检查有用,对产出的JS无影响,增加类型不会污染JS源文件。

关于tsconfig.json

可以通过 tsc –init 创建tsconfig.json文件,如下:

{
  "compilerOptions": {
    "target": "es2015",                          /* 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": ["es2015"],                             /* Specify library files to be included in the compilation. */
    "sourceMap": true,                     /* Generates corresponding '.map' file. */
    // "outFile": "./",                       /* Concatenate and emit output to single file. */
    "outDir": "dist",                        /* Redirect output structure to the directory. */
    "strict": true,                           /* Enable all strict type-checking options. */
    "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
    "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
  }
}

下面主要看几个常用配置:

配置属性 描述
include 告诉TSC在哪里找到ts文件
lib 告诉TSC当前运行时已存在的API,通常包括:ES5的bind,新增数组方法,ES6的新增方法等
module 告诉TSC将ts文件转为那种模块标准的js文件,通常有cmj,cmd,es6等
outDir 告诉TSC将转换后的文件放到哪个目录
strict 告诉TSC是否进行严格的类型检查
target 告诉TSC将ts转换成哪个版本的js,通常有ES3,ES5,ES6等
noImplicitAny 是否允许存在未定义的类型,即隐式类型。TSC不会自己猜测类型
alwaysStrict TSC会在产出的每个js文件中带上use strict语句

关于tslint

可以通过 tslint –init 创建默认的tslint.json文件,如下:

{
    "defaultSeverity": "error",
    "extends": [
        "tslint:recommended"
    ],
    "jsRules": {},
    "rules": {},
    "rulesDirectory": []
}

{}类型

当将一个变量设置为{}类型是,意味着此变量的值可以是除了null和undefined之外的任何值。

let a:{} = 1;
let b:{} = Symbol('b');
let c:{} = null; // Type 'null' is not assignable to type '{}'.
let d:{} = undefined; // Type 'undefined' is not assignable to type '{}'.

object类型

当将一个变量设置为object类型时,意味着此变量的值可以是除了字符串,数字,Symbol,null,undefined,布尔值之外的任何值。

let a:object = new Date();
let b:object = function(){};
let c:object = [];
let d:object = new RegExp('');
let e:object = true; // Type 'true' is not assignable to type 'object'.
let f:object = Symbol(); // Type 'symbol' is not assignable to type 'object'.
let g:object = 1; // Type '1' is not assignable to type 'object'.
let h:object = '1'; // Type '"1"' is not assignable to type 'object'.

Object类型

同{}类型。

Value {} object Object
{} Yes Yes Yes
[‘a’] Yes Yes Yes
function(){} Yes Yes Yes
new String(‘a’) Yes Yes Yes
‘a’ Yes No Yes
1 Yes No Yes
Symbol() Yes No Yes
true Yes No Yes
null No No No
undefined No No No

[]类型

当一个变量声明为[]类型时,表示变量的值必须为空数组。如果隐式声明为[],则表示元素的类型为any,即任意类型的值。如:

let a:[] = [];
a = [1]; // Type '[number]' is not assignable to type '[]'.
let b = []; // 隐式声明b为数组,元素类型是any类型
b.push(1);
b.push(null);

Tuples类型

此类型是array的子类型,继承自array类型。Tuples类型的数组必须显式申明其元素的类型,且数组长度不可变。如:

// 声明定长的数组
let arr: [string,number,boolean] = ['a',2,true];

// 二维数组的声明
// 分步解释:
// let data: number[] 表示声明一个元素为数字的数组
// let data: [][] 表示声明一个元素为空数组的数组
// let data: [number, number][] 表示声明一个元素为两个元素的tuples类型的数组,且tuples的两个元素必须都为number类型
// let data: [number, number?][] 表示数组的第二个元素可选
let data: [number, number?][] = [[1,2],[3],[4,5]];

// 声明不定长数组,且指定第一个元素的类型,其他元素类型任意
let data1: [string,...any[]] = ['11','s',32];

枚举类型

枚举类型主要处理两类事务:定义字符串到数字的映射或字符串到字符串的映射。TS会自动将枚举类型的每个成员映射到一个数字,默认是从0开始,也可是是显式定义数字,开始位置自己决定,如:

// 默认从0开始
enum lang {Chinese, English, Russian}; 
let a = lang.Chinese;
console.log(a, lang.English, lang.Russian); // 0, 1, 2
// 定义从3开始
enum lang {Chinese=3, English, Russian}; 
let a = lang.Chinese;
console.log(a, lang.English, lang.Russian); // 3, 4, 5
// 自定义或者自动赋值
enum lang {Chinese=3, English=6, Russian}; 
let a = lang.Chinese;
console.log(a, lang.English, lang.Russian); // 3, 6, 7

看枚举类型被TS转换后的形式,如:

var lang;
(function (lang) {
    lang[lang["Chinese"] = 3] = "Chinese";
    lang[lang["English"] = 9] = "English";
    lang[lang["Russian"] = 10] = "Russian";
})(lang || (lang = {}));
;

我们可以通过数字访问到字符串,通过字符串访问到数字,如:

console.log(lang['English'], lang[lang.English]); // 9 English

readonly修饰符

声明对象的某个属性为readonly

let a: {a:string, readonly b:number} = {a:'2', b:3};
a.b = 4; // Cannot assign to 'b' because it is a read-only property.

声明数组为只读

let as: readonly number[] = [1,2,3];
as.push(2); // Property 'push' does not exist on type 'readonly number[]'.
as.concat(3); // concat函数不会对原数组修改,而是返回新的数组,所以此处合法。

// 还可以这样声明
let arr: ReadonlyArray<string> = ['2'];
arr.push('3'); // Property 'push' does not exist on type 'readonly string[]'.
// 或者
let arr: Readonly<string[]> = ['22'];

声明类的属性为只读。类的只读属性可以在声明的时候赋值,或者构造函数中赋值,其他地方都不允许赋值。如:

class Foo{
    readonly bar = 1;
    readonly baz:string;
    constructor(){
        this.baz = 'hello';
    }
    setBaz(value:string){
        this.baz = value; // Cannot assign to 'baz' because it is a read-only property.
    }
}
console.log(new Foo().baz);

类型的组合

有时候某个变量的值可能需要取其他类型中的某一个类型,这时可以给此变量的类型设置为这些类型的并集,如:

let prop: string|number = 3;
prop = '3'; // 可以被赋值,因为prop可以为string和number类型中的一个

// 数组里可以是字符串也可以是数字
type StringOrNumber = string|number;
let a: StringOrNumber[] = []; // 或者直接这样:let a: (string|number)[] = [];
a.push(1);
a.push('a');
a.push(true); // 类型错误,不可以有布尔类型

type Cat = {name:string, purrs:boolean};
type Dog = {name:string, barks:boolean, wags:boolean}
type CatOrDogOrBoth = Cat|Dog;
let cat: CatOrDogOrBoth = {name: 'John', purrs: true};
// 类型错误 {name: 'John', barks: false} 不属于Cat和Dog中的任何一个类型
let cat2: CatOrDogOrBoth = {name: 'John', barks: false}; 
// 类型错误,同上
let cat3: CatOrDogOrBoth = {name: 'John', wags: false};
// 类型错误, 同上
let cat4: CatOrDogOrBoth = {barks: true, wags: false};
// 属于Cat类型,因为没有barks属性,即不是Dog类型,且完全拥有Cat类型定义的所有属性
let cat5: CatOrDogOrBoth = {name: 'John', purrs: true, wags: false};
// 既是Cat类型也是Dog类型
let cat6: CatOrDogOrBoth = {name: 'John', barks: false, wags: false, purrs:false}

猜你喜欢

转载自www.cnblogs.com/ywxgod/p/11730023.html
今日推荐