typeScript笔记(一)
对于刚入门 TypeScript 的小伙伴 使用线上的 TypeScript Playground 来学习新的语法或新特性。
TypeScript Playground:www.typescriptlang.org/play/
1.基础类型
const a:string = 'aa'
const b:number = 123
const c: boolean = true
const d:null = null
const e:undefined = undefined
默认情况下null和undefined是所有类型的子类型,可以把null和undefined赋值给其它任何类型:
let num: number = 1;
num = null;
num = undefined;
// null 和 undefined 赋值给 boolean
let bool: boolean = false;
bool = null;
bool = undefined;
// null 和 undefined 赋值给 object
let obj: object = {};
obj = null;
obj = undefined;
2.数组
let arr :string[] = ['a','b','c'] //元素全部是字符串数组
let arr1: number[] = [1,2,3] //元素全部是数字的数组
let arr2: boolean[] = [true,false,true] //元素全部是布尔值的数组
let arr3: Object[] = [{'name':'a'}] //元素是对象的数组
let list: Array<number> = [1, 2, 3]; // Array<number>泛型语法
3.对象
对于对象类型的描述我们需要用关键词interface来进行类型约束:
let obj={
name:'小明',
age:12,
sex:'男',
isFun:true
}
interface UserInfo{
name:string,
age:number,
sex:string,
isFun:boolean
}
let obj:UserInfo={
name:'小明',
age:12,
sex:'男',
isFun:true
}
而接口加上数组类型,就可以描述一个成员是对象的数组类型:
let userList:UserInfo[] = [
{
name:'小明',
age:12,
sex:'男',
isFun:true,
info:{
class:'3年2班',
score:80
}
},
{
name:'小红',
age:11,
sex:'女',
isFun:true,
info:{
class:'3年2班',
score:90
}
},
{
name:'小波',
age:12,
sex:'男',
isFun:true,
info:{
class:'3年2班',
score:70
}
}
]
假如我需要将sex类型变为可选类型可以在接口中定义可选标记 加个问号
interface User{
name:string,
age:number,
sex?:string
}
4.枚举enum,
使用枚举我们可以定义一些带名字的常量。 使用枚举可以清晰地表达意图或创建一组有区别的用例。 TypeScript 支持数字的和基于字符串的枚举。
enum Direction {
NORTH,
SOUTH,
EAST,
WEST,
}
let dir: Direction = Direction.NORTH;
对于es6中的map和set数据类型进行类型约束
let set = new Set<number>()
set.add(1);
set.add('2'); // X 类型“string”的参数不能赋给类型“number”的参数。
const map = new Map<number, string>();
//约束key只能是number类型 value只能是srting类型
map.set(1, '1');
map.set('2', '2'); // X 类型“string”的参数不能赋给类型“number”的参数。
5.Any类型
在 TypeScript 中,任何类型都可以被归为 any 类型。这让 any 类型成为了类型系统的顶级类型(也被称作全局超级类型)
any 类型本质上是类型系统的一个逃逸舱。作为开发者,这给了我们很大的自由:TypeScript 允许我们对 any 类型的值执行任何操作,而无需事先执行任何形式的检查。比如:
let notSure: any = 666;
notSure = "Semlinker";
notSure = false;
let value: any;
value.foo.bar; // OK
value.trim(); // OK
value(); // OK
new value(); // OK
value[0][1]; // OK
6. Unknown 类型
就像所有类型都可以赋值给 any,所有类型也都可以赋值给 unknown。这使得 unknown 成为 TypeScript 类型系统的另一种顶级类型(另一种是 any)。下面我们来看一下 unknown 类型的使用示例:
let value: unknown;
value = true; // OK
value = 42; // OK
value = "Hello World"; // OK
value = []; // OK
value = {}; // OK
value = Math.random; // OK
value = null; // OK
value = undefined; // OK
value = new TypeError(); // OK
value = Symbol("type"); // OK
unknown 类型只能被赋值给 any 类型和 unknown 类型本身,被赋值其他类型会报错
let value: unknown;
let value1: unknown = value; // OK
let value2: any = value; // OK
let value3: boolean = value; // Error
let value4: number = value; // Error
let value5: string = value; // Error
let value6: object = value; // Error
let value7: any[] = value; // Error
let value8: Function = value; // Error
7.Tuple 元组类型
如果存储的元素数据类型不同,则需要使用元组。
元组中允许存储不同类型的元素,元组可以作为参数传递给函数
let mytuple = [10,"Runoob"];
元组的特点:
-
元组可以包含多种不同类型的数据,但每个数据的类型是固定的,按照声明的顺序排列。
-
元组的长度是固定的,一旦声明,就不能改变。你不能往元组中添加或删除元素。
-
可以通过索引来访问元组中的元素,索引从 0 开始。
-
元组的类型根据声明时的类型推断来确定,可以在声明时明确指定类型。
-
如果访问超出了元组的索引范围,TypeScript 将会报错。
8.Function(函数)
在TS中函数也是一种数据类型,可以使用Function来表示一个泛用的函数。
如果你希望函数返回的是一个空:
const normal = ():void=>{
}
有返回值的正常函数
const fn: Function = function (a: number, b: number) {
return a + b
}
我们可以在函数括号后面增加返回值类型
const fn: Function = function (a: number, b: number): number {
return a + b
}
箭头函数的写法
const fn: Function = (a: number, b: number): number => {
return a + b
}
9.泛型
泛型就是给我们的代码增加一种相对宽泛的类型约束。在TypeScript中,我们定义一个变量,我们可以赋予其一种确定的类型。使得我们的代码具有更好的维护性,但是在增强代码的可维护性同时,我们又要考虑代码应该具有一定的灵活性。使得在未来,代码也能被复用。于是泛型就在这个背景下出现了
其中 T 代表 Type,在定义泛型时通常用作第一个类型变量名称。但实际上 T 可以用任何有效名称代替。除了 T 之外,以下是常见泛型变量代表的意思:
- K(Key):表示对象中的键类型;
- V(Value):表示对象中的值类型;
- E(Element):表示元素类型。
const printFun = <T>(value: T): T => {
console.log(value);
return value;
};
printFun(233);
其实并不是只能定义一个类型变量,我们可以引入希望定义的任何数量的类型变量。比如我们引入一个新的类型变量 U,用于扩展我们定义的 identity 函数:
function identity <T, U>(value: T, message: U) : T {
console.log(message);
return value;
}
console.log(identity<number, string>(68, "Semlinker"))
9.1泛型接口
interface 接口名称 {
属性名: 属性类型
函数名(参数类型列表): 返回值类型
}
interface GenericIdentityFn<T> {
(arg: T): T;
}
interface是我们在使用TS的时候,最常用的关键字。
interface Person {
name: string;
age: number;
}
const me: Person = {
name: "sunny",
age: 18,
};
//改造一下
interface Person<J, K> {
name: J;
age: K;
}
const me: Person<string, number> = {
name: "sunny",
age: 18,
};
10.extends
extends 是 typeScript 中的关键字。在 typeScript 的类型编程世界里面,它所扮演的角色实在是太重要了,所以,我们不得不需要重视它,深入学习它。在我看来,掌握它就是进入高级 typeScript 类型编程世界的敲门砖。但是,现实是,它在不同的上下文中,具体不同的,相差很大的语义。如果没有深入地对此进行梳理,它会给开发者带来很大的困惑。
extends的几个语义
- 用于表达类型组合;
- 用于表达面向对象中「类」的继承
- 用于表达泛型的类型约束;
- 在条件类型(conditional type)中,充当类型表达式,用于求值。
10.1 extends 与 类型组合/类继承
extends 可以跟 interface 结合起来使用,用于表达类型组合。
interface Animal {
name: string
}
interface Dog extends Animal {
sayHello: () => void
}
// dog具有Animal的name属性。
const dog: Dog = {
name: 'tom',
sayHello: function() {
}
}
10.2约束类的继承
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
}
class Dog extends Animal {
breed: string;
constructor(name: string, breed: string) {
super(name);
this.breed = breed;
}
}
const myDog = new Dog("Fido", "Golden Retriever");
console.log(myDog.name); // 访问父类属性
console.log(myDog.breed); // 访问子类属性
10.3约束泛型类型参数
interface Person<J, K> {
name: J;
age: K;
}
const printFun = <T extends Person<string, number>, S>(
person: T,
msg: S
): S => {
console.log(person.age);
console.log(person.name);
return msg;
};
printFun({ name: "sunny", age: 18 }, "success");
11.接口类型
11.1 基本用法
interface FullName{
firstName:string
lastName:string
}
let obj = {
firstName:'Jonathan',
lastName:'Lee'
};
//{firstName, lastName}使用了解构赋值
function say({firstName, lastName}:FullName):void {
console.log(`我的姓名是:${firstName}_${lastName}`);
}
say(obj);
11.2 接口的写法
interface 接口名称 {
属性名: 属性类型
函数名(参数类型列表): 返回值类型
}
interface Animal {
color: string
showColor: () => string
}
11.3 只读属性
interface Animal {
readonly color: string
}
const animal: Animal = {
color: "black"
}
animal.color = "white"
上述代码中会在编译前报错:无法分配到 color ,因为它是只读属性
12.函数
可选参数
函数参数可以被标记为可选的,这意味着在调用函数时可以省略这个参数。要使参数成为可选参数,写法与接口的可选属性一样,在参数名后面加上一个问号?
function foo(params?: string): void {
console.log(params)
}
13.interface 和 type 的区别
在 TypeScript 中,interface 是一种声明对象的结构,它描述了对象应该具有的属性和方法。而 type 是用来定义自定义类型的关键字,它可以表示任何类型,不仅限于对象。
14.tsconfig.json配置文件
tsconfig.json文件通过tsc --init命令生成的
"compilerOptions": {
"incremental": true, // TS编译器在第一次编译之后会生成一个存储编译信息的文件,第二次编译会在第一次的基础上进行增量编译,可以提高编译的速度
"tsBuildInfoFile": "./buildFile", // 增量编译文件的存储位置
"diagnostics": true, // 打印诊断信息
"target": "ES5", // 目标语言的版本
"module": "CommonJS", // 生成代码的模板标准
"outFile": "./app.js", // 将多个相互依赖的文件生成一个文件,可以用在AMD模块中,即开启时应设置"module": "AMD",
"lib": ["DOM", "ES2015", "ScriptHost", "ES2019.Array"], // TS需要引用的库,即声明文件,es5 默认引用dom、es5、scripthost,如需要使用es的高级版本特性,通常都需要配置,如es8的数组新特性需要引入"ES2019.Array",
"allowJS": true, // 允许编译器编译JS,JSX文件
"checkJs": true, // 允许在JS文件中报错,通常与allowJS一起使用
"outDir": "./dist", // 指定输出目录
"rootDir": "./", // 指定输出文件目录(用于输出),用于控制输出目录结构
"declaration": true, // 生成声明文件,开启后会自动生成声明文件
"declarationDir": "./file", // 指定生成声明文件存放目录
"emitDeclarationOnly": true, // 只生成声明文件,而不会生成js文件
"sourceMap": true, // 生成目标文件的sourceMap文件
"inlineSourceMap": true, // 生成目标文件的inline SourceMap,inline SourceMap会包含在生成的js文件中
"declarationMap": true, // 为声明文件生成sourceMap
"typeRoots": [], // 声明文件目录,默认时node_modules/@types
"types": [], // 加载的声明文件包
"removeComments":true, // 删除注释
"noEmit": true, // 不输出文件,即编译后不会生成任何js文件
"noEmitOnError": true, // 发送错误时不输出任何文件
"noEmitHelpers": true, // 不生成helper函数,减小体积,需要额外安装,常配合importHelpers一起使用
"importHelpers": true, // 通过tslib引入helper函数,文件必须是模块
"downlevelIteration": true, // 降级遍历器实现,如果目标源是es3/5,那么遍历器会有降级的实现
"strict": true, // 开启所有严格的类型检查
"alwaysStrict": true, // 在代码中注入'use strict'
"noImplicitAny": true, // 不允许隐式的any类型
"strictNullChecks": true, // 不允许把null、undefined赋值给其他类型的变量
"strictFunctionTypes": true, // 不允许函数参数双向协变
"strictPropertyInitialization": true, // 类的实例属性必须初始化
"strictBindCallApply": true, // 严格的bind/call/apply检查
"noImplicitThis": true, // 不允许this有隐式的any类型
"noUnusedLocals": true, // 检查只声明、未使用的局部变量(只提示不报错)
"noUnusedParameters": true, // 检查未使用的函数参数(只提示不报错)
"noFallthroughCasesInSwitch": true, // 防止switch语句贯穿(即如果没有break语句后面不会执行)
"noImplicitReturns": true, //每个分支都会有返回值
"esModuleInterop": true, // 允许export=导出,由import from 导入
"allowUmdGlobalAccess": true, // 允许在模块中全局变量的方式访问umd模块
"moduleResolution": "node", // 模块解析策略,ts默认用node的解析策略,即相对的方式导入
"baseUrl": "./", // 解析非相对模块的基地址,默认是当前目录
"paths": { // 路径映射,相对于baseUrl
// 如使用jq时不想使用默认版本,而需要手动指定版本,可进行如下配置
"jquery": ["node_modules/jquery/dist/jquery.min.js"]
},
"rootDirs": ["src","out"], // 将多个目录放在一个虚拟目录下,用于运行时,即编译后引入文件的位置可能发生变化,这也设置可以虚拟src和out在同一个目录下,不用再去改变路径也不会报错
"listEmittedFiles": true, // 打印输出文件
"listFiles": true// 打印编译的文件(包括引用的声明文件)
}
// 指定一个匹配列表(属于自动指定该路径下的所有ts相关文件)
"include": [
"src/**/*"
],
// 指定一个排除列表(include的反向操作)
"exclude": [
"demo.ts"
],
// 指定哪些文件使用该配置(属于手动一个个指定文件)
"files": [
"demo.ts"
]
15.三斜线指令
三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。
三斜线指令是包含单个XML标签的单行注释。 注释的内容会做为编译器指令使用。
三斜线指令仅可放在包含它的文件的最顶端。 一个三斜线指令的前面只能出现单行或多行注释,这包括其它的三斜线指令。 如果它们出现在一个语句或声明之后,那么它们会被当做普通的单行注释,并且不具有特殊的涵义。
/// 指令是三斜线指令中最常见的一种。 它用于声明文件间的 依赖。
三斜线引用告诉编译器在编译过程中要引入的额外的文件。
你也可以把它理解能import,它可以告诉编译器在编译过程中要引入的额外的文件
例如a.ts
namespace A {
export const fn = () => 'a'
}
b.ts
namespace A {
export const fn2 = () => 'b'
}
index.ts
引入之后直接可以使用变量A
///<reference path="./index2.ts" />
///<reference path="./index3.ts" />
console.log(A);
声明文件引入
例如,把 /// 引入到声明文件,表明这个文件使用了 @types/node/index.d.ts里面声明的名字; 并且,这个包需要在编译阶段与声明文件一起被包含进来。
仅当在你需要写一个d.ts文件时才使用这个指令。
/// 注意事项:
如果你在配置文件 配置了noResolve 或者自身调用自身文件会报错