从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}
|
请发表评论