1.基础数据类型(以下内容 大部分搬运于TypeScript官网 之所以有这篇文章 是为了学习的时候码一遍加深记忆 大家可以按需查看或者直接访问官网)
布尔值
let isDone: boolean = false;
数字
let num: number = 1;
字符串
let name: string = "augus"
数组
有两种方式可以定义数组 第一种,可以在元素类型后面接上 [] 第二种
方式是使用数组泛型,Array<元素类型>
let arr: number[] = [1, 2, 3]
或
let arr:Array<number> = [1, 2, 3]
元组
元组类型允许表示一个已知元素数量和类型的数组,各元素的类型不必相同。 比如,你可以定义一对值分别为 string
和number
类型的元组。
let x: [string, number];
// Initialize it
x = ['hello', 10]; // OK
// Initialize it incorrectly
x = [10, 'hello']; // Error
枚举
enum
类型是对JavaScript标准数据类型的一个补充。 像C#等其它语言一样,使用枚举类型可以为一组数值赋予友好的名字。
enum Color {Red = 1, Green = 2, Blue = 4}
let c: Color = Color.Green;
Any
编程阶段还不清楚类型的变量可以指定为any类型 例如 我们对notSure赋值了很多次 每一次都是不同的数据类型 这样并不会报错
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
不确定数组内是什么数据类型的也很适用any
let list: any[] = [true, 20, "lee"];
list[1] = "www";
在对现有代码进行改写的时候,any
类型是十分有用的 你可能认为 Object
有相似的作用 但是 Object
类型的变量只是允许你给它赋任意值 - 但是却不能够在它上面调用任意的方法,即便它真的有这些方法 例如如下内容 any调用方法是不会报错的 object则会报错
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn't check)
let prettySure: object = 4;
prettySure.toFixed(); // Error: Property 'toFixed' doesn't exist on type 'Object'.
Void
某种程度上来说,void
类型像是与any
类型相反,它表示没有任何类型 当一个函数没有返回值时,你通常会见到其返回值类型是 void
function warnUser(): void {
console.log("This is my warning message");
}
声明一个void
类型的变量没有什么大用,因为你只能为它赋予undefined
和null
let unusable: void = undefined;
Null和Undefined
TypeScript里,undefined
和null
两者各自有自己的类型分别叫做undefined
和null
。 和 void
相似,它们的本身的类型用处不是很大:
let u: undefined = undefined;
let n: null = null;
默认情况下null
和undefined
是所有类型的子类型。 就是说你可以把 null
和undefined
赋值给number
类型的变量。
Never
never
类型表示的是那些永不存在的值的类型 例如, never
类型是那些总是会抛出异常或根本就不会有返回值的函数表达式或箭头函数表达式的返回值类型
never
类型是任何类型的子类型,也可以赋值给任何类型;然而,没有类型是never
的子类型或可以赋值给never
类型(除了never
本身之外)。 即使 any
也不可以赋值给never
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
throw new Error(message);
}
Object
object
表示非原始类型,也就是除number
,string
,boolean
,symbol
,null
或undefined
之外的类型
let obj: object = {
name: "augus",
age: 27
}
类型断言
有时候你会遇到这样的情况,你会比TypeScript更了解某个值的详细信息。 通常这会发生在你清楚地知道一个实体具有比它现有类型更确切的类型
通过类型断言这种方式可以告诉编译器,“相信我,我知道自己在干什么”。 类型断言好比其它语言里的类型转换,但是不进行特殊的数据检查和解构
类型断言有两种形式。 其一是“尖括号”语法 第二种是as
let someValue: any = "this is a string";
let strLength: number = (<string>someValue).length;
或
let strLength: number = (someValue as string).length;
接口
接口的作用就是为类型命名和为你的代码或第三方代码定义契约
interface LabelledValue {
label: string;
}
function printLabel(labelledObj: LabelledValue) {
console.log(labelledObj.label);
}
let myObj = {size: 10, label: "Size 10 Object"};
printLabel(myObj);
接口可选属性
接口里的属性不全都是必需的。 有些是只在某些条件下存在,或者根本不存在。所以我们可以在可选属性名字定义的后面加一个?
符号
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig) {
// 要处理的逻辑
}
接口额外的属性检查以及解决办法
interface SquareConfig {
color?: string;
width?: number;
}
function createSquare(config: SquareConfig){
// ...
}
let mySquare = createSquare({ colour: "red", width: 100 });
// error: 'colour' not expected in type 'SquareConfig'
我们可以看到传入createSquare
的参数拼写为colour
而不是color
当将它们赋值给变量或作为参数传递的时候。 如果一个对象字面量存在任何“目标类型”不包含的属性时,将会报错
绕开这些检查非常简单。 最简便的方法是使用类型断言:
let mySquare = createSquare({ width: 100, opacity: 0.5 } as SquareConfig);
然而,最佳的方式是能够添加一个字符串索引签名,前提是你能够确定这个对象可能具有某些做为特殊用途使用的额外属性。 如果 SquareConfig
带有上面定义的类型的color
和width
属性,并且还会带有任意数量的其它属性,那么我们可以这样定义它:
interface SquareConfig {
color?: string;
width?: number;
[propName: string]: any;
}
这就意味着 不是color和width的其他任意属性 会无所谓它的类型
还有最后一种跳过这些检查的方式,这可能会让你感到惊讶,它就是将这个对象赋值给一个另一个变量: 因为 squareOptions
不会经过额外属性检查,所以编译器不会报错。
let squareOptions = { colour: "red", width: 100 };
let mySquare = createSquare(squareOptions);
只读属性
一些对象属性只能在对象刚刚创建的时候修改其值。 你可以在属性名前用 readonly
来指定只读属性:
interface Point {
readonly x: number;
readonly y: number;
}
你可以通过赋值一个对象字面量来构造一个Point
。 赋值后, x
和y
再也不能被改变了。
let p1: Point = { x: 10, y: 20 };
p1.x = 5; // error!
TypeScript具有ReadonlyArray<T>
类型,它与Array<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!
上面代码的最后一行,可以看到就算把整个ReadonlyArray
赋值到一个普通数组也是不可以的。 但是你可以用类型断言重写:
let a = ro as number[];
函数类型
interface SearchFunc {
(source: string, subString: string): boolean;
}
let mySearch: SearchFunc;
mySearch = function(source: string, subString: string) {
let result = source.search(subString);
return result > -1;
}
命名空间
随着更多验证器的加入,我们需要一种手段来组织代码,以便于在记录它们类型的同时还不用担心与其它对象产生命名冲突。 因此,我们把验证器包裹到一个命名空间内,而不是把它们放在全局命名空间下。
下面的例子里,把所有与验证器相关的类型都放到一个叫做Validation
的命名空间里。 因为我们想让这些接口和类在命名空间之外也是可访问的,所以需要使用 export
。
namespace Validation {
export interface StringValidator {
isAcceptable(s: string): boolean;
}
const lettersRegexp = /^[A-Za-z]+$/;
const numberRegexp = /^[0-9]+$/;
export class LettersOnlyValidator implements StringValidator {
isAcceptable(s: string) {
return lettersRegexp.test(s);
}
}
export class ZipCodeValidator implements StringValidator {
isAcceptable(s: string) {
return s.length === 5 && numberRegexp.test(s);
}
}
}
// Some samples to try
let strings = ["Hello", "98052", "101"];
// Validators to use
let validators: { [s: string]: Validation.StringValidator; } = {};
validators["ZIP code"] = new Validation.ZipCodeValidator();
validators["Letters only"] = new Validation.LettersOnlyValidator();
// Show whether each string passed each validator
for (let s of strings) {
for (let name in validators) {
console.log(`"${ s }" - ${ validators[name].isAcceptable(s) ? "matches" : "does not match" } ${ name }`);
}
}
别名
另一种简化命名空间操作的方法是使用import q = x.y.z
给常用的对象起一个短的名字。 不要与用来加载模块的 import x = require('name')
语法弄混了,这里的语法是为指定的符号创建一个别名。 你可以用这种方法为任意标识符创建别名,也包括导入的模块中的对象。
namespace Shapes {
export namespace Polygons {
export class Triangle { }
export class Square { }
}
}
import polygons = Shapes.Polygons;
let sq = new polygons.Square(); // Same as "new Shapes.Polygons.Square()"
外部命名空间
流行的程序库D3在全局对象d3
里定义它的功能。 因为这个库通过一个 <script>
标签加载(不是通过模块加载器),它的声明文件使用内部模块来定义它的类型。 为了让TypeScript编译器识别它的类型,我们使用外部命名空间声明。 比如,我们可以像下面这样写:
declare namespace D3 {
export interface Selectors {
select: {
(selector: string): Selection;
(element: EventTarget): Selection;
};
}
export interface Event {
x: number;
y: number;
}
export interface Base extends Selectors {
event: Event;
}
}
declare var d3: D3.Base;