# 基础
# 类型
给变量提供一个确定的类型叫做类型注解
# 基本类型
// number
let tn: number = 1;
let tn1: number = 0xf00d;
// string
let ts: string = "1";
// boolean
let tb: boolean = true;
// symbol
let ts: symbol = Symbol("1");
// null
let tnull: null = null;
// undefined
let tu: undefined = undefined;
// never
// 没有类型可以分配
function error(message: string): never {
throw new Error(message);
}
// never 可以分配给其他类型
// 其他类型不能分配给never类型
type Bool = never extends "a" ? string : number; // string
strictNullChecks 可以设置null和undefined是否可以赋值给基础类型
# 数组
let ta: number[] = [1, 2];
let ta1: Array<number> = [1, 2]; // 通过定义的接口interface Array
// 联合类型数组,一般通过别名来定义联合类型
let ta2: number | string = [1, 2, "1"];
# 元组
确定长度的数组,类型也必须确定
let tuple: [string, number] = ["str", 111];
console.log(tuple[2]); // 会直接报错
可变元祖
let c: [number, ...any[]] = [2, "a", 3, "b"];
# 特殊类型
# any
// 任意类型
let no: any = 4;
no = "1";
no = [1];
# void
// 没有返回值
function v(): void {
console.log(1);
}
# enum
// 默认从0开始
enum Color {
red,
green,
}
// 从1开始
enum Color1 {
red = 1,
green,
}
const c: Color = Color.red; // 0
# 对象
非原始类型
const obj: object = { a: 1 };
# 类型推断
如果不主动定义类型,则会根据定义自动推断出类型
let tnumber = 1;
# 类型断言
强制转化为对应的类型
// 尖括号
function fn(val: any) {
console.log((<Array<number>>val).slice());
}
const inputValue = (<HTMLInputElement>oInput).value;
// as
function fn(val: any) {
console.log((val as Array<number>).slice());
}
fn([1, 2]);
# 非空断言
- ! 非空断言,一定是存在的
- ?表示可能存在,可能不存在,一种语法糖,会编译成三元。
- 可以用在函数参数,接口定义等定义/使用变量的地方
function f(data?: string) {
const a = data!.toString();
console.log(a);
}
# 常量断言
as const 作为关键词 ,禁止修改
const aaa = 1 as const; // 禁止修改
# 接口
定义对象,类,函数的结构信息
interface People {
name: string;
age?: number; // 可选属性
readonly sex: number;
// 任意属性
[propName: string]: any;
}
const people: People = { name: "john", age: 12, sex: 1 };
people.sex = 2; // 报错,只读的数据不能修改
// 两个interface会合并
interface People {
phone: number;
}
# 接口继承
通过extends关键词来继承,继承后必须都满足定义的类型
interface IPeople {
id: number;
}
interface IChilren extends IPeople {
name: string;
age: number;
}
# 类型别名
可以为任何类型注解提供类型别名,一般用作联合类型和交叉类型
type Cb = () => void;
// 联合类型,只能取一
type NewType = string | number;
// 交叉类型,同时满足
type o1 = { a: string };
type o2 = { b: string };
let o1: o1 = { a: "a" };
let o2: o2 = { b: "b" };
let o3: o1 & o2 = { a: "a", b: "b" };
// 字面量类型
type name = "john" | "jack";
// 联合转化为交叉类型
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;
type I = UnionToIntersection<{ a: string } | { b: string }>; // {a:string} & {b:string}
// U extends any 的意义在于,遍历每一个联合类型的成员处理
// ((k:{a:string}) => void )| ((k:{b:string}) => void )
// 之后,能同时约束以上条件的I,为上面的父级(k: { b: number } & { a: string }) => void
// T[number] === o1 | o2 | o3
function cross<T extends object[]>(...args: T): UnionToIntersection<T[number]> {
return Object.assign({}, ...args);
}
const oAll = cross(oo1, oo2, oo3);
console.log(oAll);
# 函数
// 原则上函数参数都需要定义参数类型
// 函数返回值一般不需要定义类型,会自动推断,除非是泛型
// 参数可以传递默认值,
function add(x: number, y: number, z: number = 1): number {
return x + y + z;
}
# 剩余参数
function getRest(a: number, ...rest: number[]) {
console.log(a, rest);
}
getRest(1, 2, 3); // 1,[2,3]
# 在接口中定义函数
interface P {
fn(x: number): number;
fn2: (x: number) => number;
}
# 重载
为了表义更加清晰
// 函数重载
// 重载签名,没有函数体,不需要实现,可以有多个
function reload(n: number): number;
function reload(s: string): string;
// 实现签名
function reload(c: number | string) {
return c;
}
# 类
class People {
name: string;
constructor(name: string) {
this.name = name;
}
say(word: string) {
console.log(this.name + "say " + word);
}
}
const p = new People("john");
在ts中,默认成员均为public,同样也可以定义为private,protected。
# 泛型
定义时不明确,使用时明确的类型,也会进行类型检查
interface Ref<T> {
value: T;
}
type S = { name: string; age: number };
const ref: Ref<S> = {
value: { name: "111", age: 11 },
};
ref.value.name; // 定义ref的时候传入了S,所以ref.value就会推导出S的结构
# 参数要求一致
function add<T extends number | string>(a: T, b: T) {
console.log(a, b);
}
add(1, 2);
add("1", "2");
add(1, "2"); // 报错
# 泛型默认值(2.3+)
function add<T = number>(a: T, b: T): T {
console.log(a, b);
}
# 泛型约束
通过extends关键字来约束泛型
interface PName {
name: string;
}
// T被约束为一个对象,带有name属性
function createName<T extends PName>(arg: T): T {
return arg;
}
createName({ name: "john" }); // 限制必须传入对象包含name属性
# 泛型联合类型
如果是泛型联合类型,会进行分配,和单独使用 extends 不一样
type TBool<T> = T extends "a" ? string : number;
type TBool1 = "a" | "b" extends "a" ? string : number; // number
type TBool2 = TBool<"a" | "b">; // string | number
// never作为泛型传入就是never
type TBool3 = TBool<never>; // never
# 声明文件
主要是对类型定义的文件.d.ts,需要在tsconfig中include引入。
- 编写的
ts文件会自动生成声明文件。 - 加载第三方库的时候需要声明文件来获取类型的提示,有些库自动集成,有些需要手动安装
@types。
# 定义声明文件
声明文件的定义必须通过declare,可以通配置skipCheckLib取消,一般不建议。
declare let a; // 声明全局变量
declare const b; // 声明全局变量
declare function // 声明全局方法
declare class // 声明全局类
declare enum // 声明全局枚举
declare namespace // 声明(包含子属性)全局对象
// interface/type 可以不写declare
# 定义命名空间,防止定义重名
declare namespace JQuery {
function $(): void;
function $(selector: string): void;
}
// 使用
JQuery.$();
# 模块声明
declare module JQueryModule {
function $(n: number): void;
namespace $ {
function css(): void;
}
// export default $; // 可以用,但是不推荐
export = $;
}
使用
import $ from "./JQueryModule";
$.css();
← ts 笔记 TypeScript 挑战 →