TypeScript基础
TypeScript基础
1、变量
(1) 变量声明
在TypeScript中定义变量需要定义标识符类型。
声明了类型后TypeScript就会进行类型检测,声明的类型可以称之为类型注解;
自动类型判断;
- TS拥有自动的类型判断机制
- 当对变量的声明和赋值是同时进行的,TS编译器会自动判断变量的类型
- 所以如果你的变量的声明和赋值时同时进行的,可以省略掉类型声明
// 完整声明格式:
var/let/const 标识符: 数据类型 = 赋值;
//例:
let name:string = 'CoderKing';
// 注:类型string是小写的,和String是不同的。
// string是TypeScript中定义的字符串类型,String是ECMAScript中定义的一个类
(2) 声明变量关键字
在TypeScript定义变量(标识符)和ES6之后一致,可以使用var、let、const来定义。(已不推荐用var)
var name:string = 'CoderKing-one';
let name:string = 'CoderKing-two';
const NAME:string = 'CoderKing-three';
2、数据类型
(1) 基本类型
| 类型 | 例 | 描述 |
|---|---|---|
| number | 1, -33, 2.5 | 任意数字 |
| string | 'hi', "hi", hi | 任意字符串 |
| boolean | true、false | 布尔值true或false |
| 字面量 | 其本身 | 限制变量的值就是该字面量的值 |
| null/undefined | 和js一致 | 和js一致 |
| symbol | 和js一致 | 和js一致 |
| any | * | 任意类型 |
| unknown | * | 类型安全的any |
| void | 空值(undefined) | 没有值(或undefined) |
| never | 没有值 | 不能是任何值 |
| object | {name:'孙悟空'} | 任意的JS对象 |
| array | [1,2,3] | 任意JS数组 |
| tuple | [4,5] | 元素,TS新增类型,固定长度数组 |
| enum | enum{A, B} | 枚举,TS中新增类型 |
number
let decimal: number = 6; let hex: number = 0xf00d; let binary: number = 0b1010; let octal: number = 0o744; //大数字 let big: bigint = 100n;boolean
let flag: boolean = true flag = 20 > 30string
let color: string = "blue"; color = 'red'; 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.`;字面量
也可以使用字面量去指定变量的类型,通过字面量可以确定变量的取值范围
let color: 'red' | 'blue' | 'black'; let num: 1 | 2 | 3 | 4 | 5;null/undefined
let n1: null = null let n2: undefined = undefinedsymbol
const title1 = Symbol("title") const title2 = Symbol('title') const info = { [title1]: "程序员", [title2]: "老师" }any
// // 当进行一些类型断言 as any // 在不想给某些JavaScript添加具体的数据类型时(原生的JavaScript代码是一样) let d: any = 4; d = 'hello'; d = true;unknown
function foo() { return "abc" } function bar() { return 123 } // unknown类型只能赋值给any和unknown类型 // any类型可以赋值给任意类型 let flag = true let result: unknown // 最好不要使用any if (flag) { result = foo() } else { result = bar() } let message: string = result let num: number = result console.log(result)void
function sum(num1: number, num2: number):void { console.log(num1 + num2) } sum(20, 30) // sum("abc", "cba")never
function handleMessage(message: string | number | boolean): never { switch (typeof message) { case 'string': console.log("string处理方式处理message") break case 'number': console.log("number处理方式处理message") break case 'boolean': console.log("boolean处理方式处理message") break default: const check: never = message } } handleMessage("abc")object
// 完整写法 const info: { name: String; age: Number; } = { name: "why", age: 18, }; // ts有类型推导,可不写 const info2 = { name: "why", age: 18, };array
// 类型注解: type annotation let list: Array<number> = [1, 2, 3]; // 不推荐(react jsx中是有冲突 <div></div>) let list: number[] = [1, 2, 3]; // 推荐tuple
//元组的类型和长度是确定的 const info: [string, number, number] = ["why", 18, 1.88] const name = info[0] console.log(name.length)应用场景:
function useState(state: any) { let currentState = state const changeState = (newState: any) => { currentState = newState } const tuple: [any, (newState: any) => void] = [currentState, changeState] return tuple } const [counter, setCounter] = useState(10); setCounter(1000) const [title, setTitle] = useState("abc")enum
enum Color { Red, Green, Blue, } let c: Color = Color.Green; enum Color { Red = 1, Green, Blue, } let c: Color = Color.Green; enum Color { Red = 1, Green = 2, Blue = 4, } let c: Color = Color.Green;
(2) 类型补充
函数参数和返回值类型
// 给参数加上类型注解: num1: number, num2: number // 给返回值加上类型注释: (): number // 在开发中,通常情况下可以不写返回值的类型(自动推导) function sum(num1: number, num2: number) { return num1 + num2 } // sum(123, 321)匿名函数的参数类型
// 通常情况下, 在定义一个函数时, 都会给参数加上类型注解的 function foo(message: string) { } const names = ["abc", "cba", "nba"] // item根据上下文的环境推导出来的, 这个时候可以不添加的类型注解 // 上下文中的函数: 可以不添加类型注解 names.forEach(function(item) { console.log(item.split("")) })对象类型
// Point: x/y -> 对象类型 // {x: number, y: number} function printPoint(point: {x: number, y: number}) { console.log(point.x); console.log(point.y) } printPoint({x: 123, y: 321})可选类型
// Point: x/y/z -> 对象类型 // {x: number, y: number, z?: number} function printPoint(point: {x: number, y: number, z?: number}) { console.log(point.x) console.log(point.y) console.log(point.z) } printPoint({x: 123, y: 321}) printPoint({x: 123, y: 321, z: 111})联合类型
// number|string 联合类型 function printID(id: number|string|boolean) { // 使用联合类型的值时, 需要特别的小心 // narrow: 缩小 if (typeof id === 'string') { // TypeScript帮助确定id一定是string类型 console.log(id.toUpperCase()) } else { console.log(id) } } printID(123) printID("abc") printID(true)类型别名
// type用于定义类型别名(type alias) type IDType = string | number | boolean type PointType = { x: number y: number z?: number } function printId(id: IDType) {} function printPoint(point: PointType) {}类型断言as
// <img id="why"/> // 1.类型断言 as const el = document.getElementById("why") as HTMLImageElement; el.src = "url地址"; // 2.另外案例: Person是Student的父类 class Person {} class Student extends Person { studying() {} } function sayHello(p: Person) { (p as Student).studying(); } const stu = new Student(); sayHello(stu); // 3.了解: as any/unknown const message = "Hello World"; // const num: number = (message as unknown) as number非空类型断言
// message? -> undefined | string function printMessageLength(message?: string) { // if (message) { // console.log(message.length) // } // vue3源码 console.log(message!.length); } printMessageLength("aaaa"); printMessageLength("hello world");可选链的使用
type Person = { name: string friend?: { name: string age?: number, girlFriend?: { name: string } } } const info: Person = { name: "why", friend: { name: "kobe", girlFriend: { name: "lily" } } } // 另外一个文件中 console.log(info.name) // console.log(info.friend!.name) console.log(info.friend?.name) console.log(info.friend?.age) console.log(info.friend?.girlFriend?.name) // if (info.friend) { // console.log(info.friend.name) // if (info.friend.age) { // console.log(info.friend.age) // } // }!!运算符
const message = "Hello World"; // const message = ""; // const flag = Boolean(message) // console.log(flag) const flag = !!message; console.log(flag); const flag1 = message;??运算符
let message: string | null = "Hello World"; const content = message ?? "你好啊, 李银河"; // const content = message ? message: "你好啊, 李银河" console.log(content);类型缩小
// 1.typeof的类型缩小 type IDType = number | string; function printID(id: IDType) { if (typeof id === "string") { console.log(id.toUpperCase()); } else { console.log(id); } } // 2.平等的类型缩小(=== == !== !=/switch) type Direction = "left" | "right" | "top" | "bottom"; function printDirection(direction: Direction) { // 1.if判断 // if (direction === 'left') { // console.log(direction) // } else if () // 2.switch判断 // switch (direction) { // case 'left': // console.log(direction) // break; // case ... // } } // 3.instanceof function printTime(time: string | Date) { if (time instanceof Date) { console.log(time.toUTCString()); } else { console.log(time); } } class Student { studying() {} } class Teacher { teaching() {} } function work(p: Student | Teacher) { if (p instanceof Student) { p.studying(); } else { p.teaching(); } } const stu = new Student(); work(stu); // 4. in type Fish = { swimming: () => void; }; type Dog = { running: () => void; }; function walk(animal: Fish | Dog) { if ("swimming" in animal) { animal.swimming(); } else { animal.running(); } } const fish: Fish = { swimming() { console.log("swimming"); }, }; walk(fish);
3、函数详解
(1) 函数的类型
// 1.函数作为参数时, 在参数中如何编写类型
function foo() {}
type FooFnType = () => void;
function bar(fn: FooFnType) {
fn();
}
bar(foo);
// 2.定义常量时, 编写函数的类型
type AddFnType = (num1: number, num2: number) => number;
const add: AddFnType = (a1: number, a2: number) => {
return a1 + a2;
};
(2) 参数的可选类型
// 可选类型是必须写在必选类型的后面的
// y -> undefined | number
function foo(x: number, y?: number) {}
foo(20, 30);
foo(20);
(3) 参数的默认值
// 必传参数 - 有默认值的参数 - 可选参数
function foo(y: number, x: number = 20) {
console.log(x, y);
}
foo(30);
(4) 函数的剩余参数
// function sum(num1: number, num2: number) {
// return num1 + num2
// }
function sum(initalNum: number, ...nums: number[]) {
let total = initalNum;
for (const num of nums) {
total += num;
}
return total;
}
console.log(sum(20, 30));
console.log(sum(20, 30, 40));
console.log(sum(20, 30, 40, 50));
(5) this的默认推导
// this是可以被推导出来 info对象(TypeScript推导出来)
const info = {
name: "why",
eating() {
console.log(this.name + " eating")
}
}
info.eating()
(6) this的不明确的类型
type ThisType = { name: string };
function eating(this: ThisType, message: string) {
console.log(this.name + " eating", message);
}
const info = {
name: "why",
eating: eating,
};
// 隐式绑定
info.eating("哈哈哈");
// 显示绑定
eating.call({ name: "kobe" }, "呵呵呵");
eating.apply({ name: "james" }, ["嘿嘿嘿"]);
(7) 函数的重载
联合类型
/** * 通过联合类型有两个缺点: * 1.进行很多的逻辑判断(类型缩小) * 2.返回值的类型依然是不能确定 */ function add(a1: number | string, a2: number | string) { if (typeof a1 === "number" && typeof a2 === "number") { return a1 + a2; } else if (typeof a1 === "string" && typeof a2 === "string") { return a1 + a2; } // return a1 + a2; } add(10, 20);函数重载
// 函数的重载: 函数的名称相同, 但是参数不同的几个函数, 就是函数的重载 function add(num1: number, num2: number): number; // 没函数体 function add(num1: string, num2: string): string; function add(num1: any, num2: any): any { if (typeof num1 === "string" && typeof num2 === "string") { return num1.length + num2.length; } return num1 + num2; } const result = add(20, 30); const result2 = add("abc", "cba"); console.log(result); console.log(result2); console.log(console.log); // 在函数的重载中, 实现函数是不能直接被调用的 // add({name: "why"}, {age: 18})
