值类型

// 字符串
let myNname: string = "朝阳";

// 数字
let num: number = 10;

// 布尔类型
let ifLogin: boolean = true;
// 布尔类型支持赋值计算之后结果是布尔值的表达式
let bool: boolean = !!0

// null
let n: null = null;

// undefined
let u: undefined = undefined;

// symbol
let s: symbol = Symbol();

TS 官方推荐使用 string , 不推荐用 String , 因为 String 是包装对象,Number,Boolean 等同理。

let myname: string = "朝阳";

myname = new String("你好"); // 报错:不能将类型“String”分配给类型“string”。“string”是基元(基础数据类型),但“String”是包装器对象。

String 既能赋值基础字符串,也能赋值包装对象。

let myname: String = "朝阳";

myname = new String("你好");

Typescript 【详解】类型声明_typescript

数组 []

// 空数组
let arr: [] = [];

// 元素只能是数字的数组(其他类型的写法类似)
let arr1: number[] = [1, 2];

// 元素只能是数字或字符串的数组(| 表示或的关系)
let arr2: (number | string)[] = [1, "朝阳"];

// 即是number类型也可能是string数组
const numbers1: number[] | string[] = ['123', '333'] // 正确
const numbers2: number[] | string[] = [123, '333'] // 错误

// 对象数组
let todoList: {
  id: number;
  label: string;
  done: boolean;
}[] = [
  {
    id: 1,
    label: "吃饭",
    done: false,
  },
  {
    id: 2,
    label: "编程",
    done: false,
  },
];

// 使用类型别名(type alias)
type User = { name: string; age: number }

// 存储对象类型的内容
const objectArr: User[] = [
  {
    name: 'zws',
    age: 18
  }
]

// 构造函数声明类型
let arr_1: Array<number> = [1, 2];
let arr_2: Array<number | string> = [1, "朝阳"];

对象 {}

// 空对象
let o: {} = {};
let o2: object = {};


// 必选属性的对象(赋值时,声明的属性必须有!)
let user: {
  name: string;
  age: number;
} = {
  name: "朝阳",
  age: 35,
};

// 可选属性的对象(可选属性需写在必选属性的后面!)
let user2: {
  name: string;
  age?: number;
} = {
  name: "晚霞",
};

对象类型的描述,可以用 , ; 或换行分隔,如

let user1: {
  name: string;
  age: number
};

let user2: {
  name: string,
  age: number
};

let user3: {
  name: string
  age: number
};

Object 、object 和 {} 的区别

  • Object (首字母大写)【用得很少,因类型太宽泛】 和 {} 的类型声明最抽象,对象、数组、基础数据类型(除 null , undefined)都能赋值。
  • object (首字母小写)【用得很少,因类型太宽泛】更具体些,类似于 { [key: string]: any } ,可以给它赋值对象和数组,不能分配基础数据类型
  • { [key: string]: string } 则最具体,只能赋值键值为字符串的对象。
var p: {}; // 或 Object
p = { prop: 0 }; // OK
p = []; // OK
p = 42; // OK
p = "string"; // OK
p = false; // OK
p = null; // Error
p = undefined; // Error

var o: object;
o = { prop: 0 }; // OK
o = []; // OK
o = 42; // Error
o = "string"; // Error
o = false; // Error
o = null; // Error
o = undefined; // Error

var q: { [key: string]: any };
q = { prop: 0 }; // OK
q = []; // OK
q = 42; // Error
q = "string"; // Error
q = false; // Error
q = null; // Error
q = undefined; // Error

var r: { [key: string]: string };
r = { prop: 'string' }; // OK
r = { prop: 0 }; // Error
r = []; // Error
r = 42; // Error
r = "string"; // Error
r = false; // Error
r = null; // Error
r = undefined; // Error

索引签名

允许定义对象可以具有任意数量的属性,这些属性的键和类型是可变的,常用于描述类型不确定的属性(具有动态属性的对象)。

let person: {
  name: string;
  age?: number;
  // 下方为索引签名,表示本对象可以有任意数量的属性,属性值可以为任意类型。
  [key: string]: any; // 通常用 key ,实际可以写任意名称,如 index 等。
};

person = { name: "朝阳", age: 35, gender: "男", city: "成都" };

函数 function

// TS 语法,声明 add 变量为函数类型,此处 => 并不表示箭头函数,而是表示函数的定义
let add: (a: number, b: number) => number; // a,b 只是形式参数,可以用任意字符串代替

add = (x, y) => {
  return x + y;
};

// 命名函数
function add(arg1: number, arg2: number): number {
  return x + y;
}

// 箭头函数
const add = (arg1: number, arg2: number): number => {
  return x + y;
};

类 class

class Person {}
const me: Person = new Person()

class Teacher {
  name: string
  age: number
}

const objectArr: Teacher[] = [
  new Teacher(),
  {
    name: 'zws',
    age: 18
  }
]

任意类型 any

当不确定变量的类型时(比如来自用户输入或第三方代码库的动态内容),可以使用,但尽量少用。

  • 任何类型的值都可以赋值给 any 类型的变量
let a: any = '你好'
a = 0

// 多数据类型的数组
let list: any[] = [1, true, "free"];
  • 未声明类型的变量,其类型就是 any
// 与 let myname:any 等效
let myname
  • any 类型的变量,可以赋值给任意类型的变量
let myname: any = "朝阳";

let yourName: number = 11;

// 不会报错!
yourName = myname;
  • 读取 any 类型数据的任何属性都不会报错

不确定的类型 unknown

  • 任何类型的值都可以赋值给 unknown 类型的变量
  • unknown 可以理解为类型安全的 any ,即 unknown 类型的变量,无法像 any 类型的变量一样,随意赋值给其他类型的变量。
  • any 与 unknown 的区别 : unknown 需要明确类型后执行操作,any 则不需要
let a: unknown = 1;

let b = a + 1; // 会报错 “a”的类型为“未知”

永不存在的类型 never

用于总会抛出异常或根本不会有返回值的函数表达式的返回值类型。
当变量被永不为真的类型保护所约束时,该变量也是 never 类型。

很少主动声明类型 never,通常是 TS 自行推导出类型 never

用途

  • 限制函数的返回类型(顺利执行的函数默认会返回 undefined,所以 never 仅适用于运行过程中会抛出异常,或永远调不完的函数)
  • 控制流程
  • 类型运算
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}

// 推断的返回值类型为never
function fail() {
    return error("Something failed");
}

// 返回never的函数必须存在无法达到的终点
function infiniteLoop(): never {
    while (true) {
    }
}

空类型 void

通常用于描述函数没有返回值

// 实际函数的返回值为 undefined
function test(): void {
}

// 实际函数的返回值为 undefined
function test(): void {
  return;
}

// 明确指定函数的返回值为 undefined
function test(): void {
  return undefined;
}

void类型的变量只能被赋予undefined

let test: void = undefined;

但 void 与 undefined 并不等效!

function test2(): void {}

let result2 = test2();

// 此处会报错,因为 TS 不建议对 void 类型的数据做进一步处理和判断!
if (result2) {
}

undefined 则不会报错

function test1(): undefined {}

let result1 = test1();

if (result1) {
}

Typescript 【详解】类型声明_赋值_02


这是 TS 官方的一种特殊处理

Typescript 【详解】类型声明_typescript_03

元组 Tuple

固定长度和类型(可以不同)的数组

let x: [string, number]; // 元组 -- 第一个元素是字符串,第二个元素是数字
x = ['hello', 10];
let x: [number, string?]; // 元组 -- 字符串元素是可选的,可有可无
let x: [number, ...string[]]; // 元组 -- 字符串元素可以是任意数量(含0个)

枚举 enum【重要】

一组常量值,不能修改,可提升语义,方便维护。

  • 枚举类型的名称通常首字母大写!

数值枚举(默认)

  • 枚举成员的值会默认递增
  • 具有反向映射
enum Direction {
  Up,
  Down,
  Left,
  Right,
}

console.log(Direction);

打印可见

{
  '0': 'Up',
  '1': 'Down',
  '2': 'Left',
  '3': 'Right',
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3
}
// 枚举三原色
enum Color {Red, Green, Blue}
// 按枚举内容的字符串取值,得到的是对应的下标(类似数组的下标,从0开始)
let c: Color = Color.Green;  // c的值为1
// 枚举方向:上下左右
enum Direction {
  Up,
  Down,
  Left,
  Right
}

// 按下标取值,可得到枚举内容的字符串
console.log(Direction[0]) // "Up"

可以自定义下标的起点

// 将默认的下标 0  改为 下标 1,则后续下标会依次递增
enum Direction {
  Up = 1,
  Down,  // 2
  Left,  // 3
  Right  // 4
}

也可以自定义任意下标,未定义的在上一个的基础上递增

enum Direction {
  Up = 11,
  Down, // 12
  Left = 6, 
  Right, // 7
}

甚至下标可以相同

enum Direction {
  Up = 11,
  Down, // 12
  Left = 11,
  Right, // 12
}

console.log(Direction.Down); // 打印 12

console.log(Direction); // 打印 { '11': 'Left', '12': 'Right', Up: 11, Down: 12, Left: 11, Right: 12 }

如果下标使用了计算值或常量,那么该字段后面紧接着的字段必须设置初始值,不能默认递增值了!

const getValue = () => {
  return 0;
};
enum ErrorIndex {
  a = getValue(),
  b, // error 枚举成员必须具有初始化的值
  c
}
enum RightIndex {
  a = getValue(),
  b = 1,
  c
}
const Start = 1;
enum Index {
  a = Start,
  b, // error 枚举成员必须具有初始化的值
  c
}

字符串枚举

即给枚举成员赋值为字符串

  • 当枚举成员为字符串时,其之后的成员也必须是字符串。
  • 没有反向映射
enum Direction {
  Up, // 未赋值,默认为0
  Down = '南',
  Left = '西',
  Right = '东'
}

常量枚举

给枚举添加 const 标注,可减少编译的代码量。

enum Direction {
  Up,
  Down,
  Left,
  Right,
}

console.log(Direction.Up);

编译为 js 后为

var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
    Direction[Direction["Left"] = 2] = "Left";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));
console.log(Direction.Up);

const enum Direction {
  Up,
  Down,
  Left,
  Right,
}

编译为 js 后为

console.log(0 /* Direction.Up */);

可见编译后的代码量,大大减少了!

事件 Event

如鼠标事件 MouseEvent

HTML元素 HTMLElement

如 input 元素 HTMLInputElement

字面量类型(了解即可)

let myname: "朝阳" = "朝阳";

则 myname 只能赋值 “朝阳” ,无法赋值其他值。