TypeScript 是 JavaScript 类型的超集,它可以编译成纯 JavaScript。
install
npm
npm install -g typescript
Visual Studio Code
https://www.typescriptlang.org/#download-links
编译
TypeScript 文件后缀名为.ts
, 需编译为 .js
文件。
tsc <filename>
config
项目根目录生成 tsconfig.json
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es5",
"jsx": "react"
},
"include": [
"./src/**/*"
]
}
webpack
npm install -g webpack
npm install --save-dev typescript awesome-typescript-loader source-map-loader
awesome-typescript-loader 可使用 ts-loader 替换。
webpack.config.js
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: __dirname + "/dist"
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json"]
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.tsx?$/, loader: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
},
// When importing a module whose path matches one of the following, just
// assume a corresponding global variable exists and use that instead.
// This is important because it allows us to avoid bundling all of our
// dependencies, which allows browsers to cache those libraries between builds.
externals: {
"react": "React",
"react-dom": "ReactDOM"
},
};
语言
变量类型
Boolean
let isDone:boolean = false;
Number
支持 二进制、八进制、十进制、十六进制的浮点数
let decimal: number = 6;
let hex: number = 0xf00d;
let binary: number = 0b1010;
let octal: number = 0o744;
String
支持 "
与 '
包裹字符串。
let color: string = "blue";
color = 'red';
同样支持末模板符串,嵌入表达式${ expr }
let fullName: string = `Bob Bobbington`;
let age: number = 37;
let sentence: string = `Hello, my name is ${ fullName }. I'll be ${ age + 1 } years old next month.`;
Array
使用 elemType[]
申明:
let list: number[] = [1, 2, 3];
使用 Array<elemType>
申明:
let list: Array<number> = [1, 2, 3];
Tuple
表示不同类型但位置固定的数组
let x: [string, number];
x = ["hello", 10]; // OK
x = [, 10] // OK
x = [10, "hello"]; // Error
x[2] = 'hello'; // OK
x[2] = 10; // OK
x[3] = 10; // OK
x[3] = 'hello'; // OK
x[2] = true; // Error
x[1] = 1; // Error
Enum
枚举类型是给一组数值更友好命名的方式,可参考 C#
中的枚举:
enum Color {Red, Green, Blue};
let c: Color = Color.Green;
默认枚举类型第一个值为 0
,第二个为 1
,逐一递增。编译成 JavaScript
为:
var Color;
(function (Color) {
Color[Color["Red"] = 0] = "Red";
Color[Color["Green"] = 1] = "Green";
Color[Color["Blue"] = 2] = "Blue";
})(Color || (Color = {}));
var c = Color.Green;
我们也能设置某个属性的初始值,其余的值上依次递增:
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green; // 2
或则定义全部值:
enum Color {Red = 1, Green = 3, Blue = 4}
let c: Color = Color.Green; // 2
枚举另一个便利的功能是可以从数值取得对应的字符名
enum Color {Red = 1, Green, Blue}
let colorName: string = Color[2]; // Green
Any
如果想声明一个不确定类型的变量,使用 any
类型的变量,这在引用第三方框架时很有用。
let noSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
Void
如果一个函数没有返回值可使用 void
function nothingWillReturn(): void {
}
给变量声明 void
类型没什么用,因为之后你只能为其赋值为 undefined
或者 null
。
Null 和 Undefined
TypeScript 中,null
和 undefined
是两种不同的类型,分别为 null
和 typescript
,同 void ,给变量声明这两种类型没什么卵用。
// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;
默认情况下,null
和 undefined
是所有其他类型的子类型。这意味着可以将数值之类赋值给 null
和undefined
类型的变量。
// 这样也可以
let u: null = undefined;
let n: undefined = null;
当使用 --strictNullChecks
标志时,null
和 undefined
类型的变量只能赋值各自的对应类型。
let u: null = undefined; // error TS2322: Type 'undefined' is not assignable to type 'null'.
let n: undefined = null; // error TS2322: Type 'null' is not assignable to type 'undefined'.
Never
tbd
类型断言
<type>
let someValue: any = 'this is a string';
let strLength: number = (<string>someValue).length;
as
let someValue: any = 'this is a string';
let strLength: number = (someValue as string).length;
let
建议使用 let 替代 var
Interface
TypeScript 的
TypeScript 只会检测在 Interface 中申明的类型:
interface Person {
firstName: string,
lastName: string
}
function greeter(person: Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
let user = { firstName: "Jane", lastName: "User" };
document.body.innerHTML = greeter(user);
类型检测并不要求属性以声明循序出现
Optional Properties(可选属性)
接口属性后面增加?
符号,表示该类型是可选的。
interface Person {
firstName?: string;
lastName? : string;
}
Readonly Properties(只读属性)
接口属性前加 readonly
修饰符表示该属性是只读属性。
interface Point {
readonly x: number;
readonly y: number;
}
ReadonlyArray<T>
可声明一个只读类型的数组类型。
let a: number[] = [1, 2, 3, 4];
let ro: ReadonlyArray<number> = a;
ro[0] = 12; // error!
ro.push(5); // error!
ro.length = 100; // error!
a = ro; // error!
readonly
vs const
区分它们办法是:readonly
用于属性修饰,而 const
用于变量修饰。
Excess Property Checks(多余属性检测)
在 TypeScsript
中如果传递了 interface
中未定义的属性,会引发错误。
interface Person {
name: string
};
function getName(person: Person) {
console.log(person.name);
}
getName({
name: 'hubery',
age: 26,
});
// error TS2345: Argument of type '{ name: string; age: number; }' is not assignable to parameter of type 'Person'.
// Object literal may only specify known properties, and 'age' does not exist in type 'Person'.
Function Types (函数类型接口)
声明函数的 params
类型以及返回值类型,这样的函数类型接口( function type interface )也叫签名。
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
为了函数类型能够正确的进行类型检查,参数的名称不需要匹配(可通过函数参宿循序去匹配)。
let mySearch: SearchFunc;
mySearch = function(src: string, sub: string): boolean {
let result = src.search(sub);
return result > -1;
}
如果你不想声明函数的参数类型,TypeScript
也可以通过上下文推断出参数类型,函数表达式返回值的类型也可以如此推断出。
let mySearch: SearchFunc;
mySearch = function(src, sub) {
let result = src.search(sub);
return result > -1;
}
Indexable Types
interface StringArray {
[index: number]: string;
}
let myArray: StringArray;
myArray = ["Bob", "Fred"];
let myStr: string = myArray[0];
定义了一个索引为 number 的字符串类型数组的索引签名
变量声明
var
let
块级作用域
let
作用域仅在块级作用域内
let
必须先声明再使用。
不可重复声明
const
let vs. const
Destructuring(解构)
数组解构
在函数中穿插使用解构寒素,并约定类型。
function f([first, second]: [number, number]) {
console.log(first);
console.log(second);
}
f([1, 2]);
对象解构
Class Types
接口实现
如 C# 与 Java 中常见用法
Class
Inheritance (继承)
extend
public
在TypeScript
里,成员都默认为 public
private
private
修饰的成员不能在声明它的类外访问
protected
protected
修饰的成员在派生类中可以访问
readonly
使用 readonly 修饰符使得属性只读,readonly 属性必须在构造函数或声明时被初始化。
class Octopus {
readonly name: string;
readonly numberOfLegs: number = 8;
constructor (theName: string) {
this.name = theName;
}
}
let dad = new Octopus("Man with the 8 strong legs");
dad.name = "Man with the 3-piece suit"; // error! name is readonly.
Parameter properties
参数属性可以方便地让我们在一个地方定义并初始化一个成员。
class Octopus {
readonly numberOfLegs: number = 8;
constructor(readonly name: string) {
}
}
Accessors(存取器)
首先,存取器要求你将编译器设置为输出ECMAScript 5或更高。 不支持降级到ECMAScript 3。 其次,只带有 get不带有 set的存取器自动被推断为 readonly。
Static Properties
static 关键词修饰成员属性,直接使用[类名.成员名]访问,静态属性存在于类本身上面而不是类的实例
Abstract Classes
抽象类做为其它派生类的基类使用。 它们一般不会直接被实例化。 不同于接口,抽象类可以包含成员的实现细节。
Function
函数类型
定义函数类型
同 JavaScript 可创建匿名函数与具名函数。
我们可以定义函数的返回值类型,但 TypeScript
根据 return 语句可以自动推断出返回值类型。
function add(x: number, y : number): number {
return x + y;
}
var add2 = function(x: number, y : number): number {
return x + y;
}
可选参数与默认值
TypeScript 中传递给函数的参数个数必须与函数期望的参数个数一致。
TypeScript 参数旁添加 ?
表示该参数是可选的,并且可选参数必须位于必须参数后面。
function buildName(firstName: string, lastName?: string) {
// ...
}
TypeScript 中也可给参数赋默认值可实现默认参数,默认参数可出现在必选参数的前面,其类型可以省略。
function buildName(firstName: string = 'test', lastName: string) {
// ...
}
function buildName(firstName = 'test', lastName: string) {
// ...
}
剩余参数
如函数接受多个参数,但不能确定参数个数,使用参数数组 ...
+ 参数名。
function(firseName" string, ...restOfName: string[]) {
return firstName + '' + restOfName.join(' ');
}
let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
this
箭头函数能保存函数创建时的 this值,而不是调用时的值。
this 箭头函数
重载
同一个函数提供多个函数类型定义来进行函数重载,TypeScript 查找重载列表,尝试使用第一个重载定义。 如果匹配的话就使用这个。 因此,在定义重载的时候,一定要把最精确的定义放在最前面。
泛型
枚举
第一枚举元素初始值为 0,其余枚举元素的值为上一个枚举成员的值递增 1。
- 不具有初始化函数并且之前的枚举成员是常数。在这种情况下,当前枚举成员的值为上一个枚举成员的值加1。但第一个枚举元素是个例外。 如果它没有初始化方法,那么它的初始值为
0
。 - 枚举成员使用常数枚举表达式初始化。 常数枚举表达式是
TypeScript
表达式的子集,它可在编译阶段求值。当一个表达式满足下面条件之一时,它就是一个常数枚举表达式:- 数字字面量
- 引用之前定义的常数枚举成员(可以是在不同的枚举类型中定义的) 如果这个成员是在同一个枚举类型中定义的,可以使用非限定名来引用。
- 带括号的常数枚举表达式
+
,-
,~
一元运算符应用于常数枚举表达式+
,-
,*
,/
,%
,<<
,>>
,>>>
,&
,|
,^
二元运算符,常数枚举表达式做为其一个操作对象。若常数枚举表达式求值后为 NaN或Infinity,则会在编译阶段报错。