TypeScript官网https://www.typescriptlang.org
js缺陷
- 没有对类型和参数进行检错、校验的功能,可能会因为一个小小的错误而导致正个程序编译不过去
TypeScript
特点
- 是拥有类型的JavaScript超集,它可以编译成普通、干净、完整的JavaScript代码
- 强大的工具,用于构建大项目
- TypeScript提供最新的和不断发展的JavaScript特性
- TypeScript需要转换成JavaScript才能编译执行
转换工具
方法一:
- 下载
npm install typescript -g
C:\Users\gqb>tsc -v
Version 4.3.5
- 编译成js
tsc 01first.ts
方法二:
- 安装
npm install ts-node -g
npm install @types/node -g
- 使用(相当于 编译+运行)
ts-node 01first.ts
方法三:
webpack环境下的ts
- 下载webpack和webpack-cli
- webpack init选择配置
string 和 String
string: TypeScript中的字符串类型
String: JavaScript的字符串包装类的类型
变量名冲突问题
- 原因:同一目录下两个相同的变量会报错
- 解决方法:在最后添加一样代码,表示这是独立模块
export {}
number类型
输出的是十进制
let num1: number = 100
//二进制
let num2: number = 0b100
//八进制
let num3: number = 0o100
//十六进制
let num4: number = 0x100
布尔类型
let flag: boolean = true
字符串
var name: string = "why"
let age: number = 18
const height: number = 1.88
类型推导/推断(默认赋值):默认情况下会将赋值的数据类型做为前面标识符的类型
let foo = "foo"
相当于
let foo:string = "foo"
数组(array)类型
// 类型注解: type annotation
const names1: Array<string> = [] // 不推荐(react jsx中是有冲突 <div></div>)
const names2: string[] = [] // 推荐
对象
const info = {
name: "why",
age: 18
}
console.log(info.name)
null和undefined
//只能是null或者undefined
let n1: null = null
let n2: undefined = undefined
symbol
const title1 = Symbol("title")
const title2 = Symbol('title')
const info = {
[title1]: "程序员",
[title2]: "老师"
}
TS独有类型
any类型
// 在不想给某些JavaScript添加具体的数据类型时(原生的JavaScript代码是一样)
let message: any = "Hello World"
message = 123
message = true
message = {
}
unknow类型
- unknown类型只能赋值给any和unknown类型
- any类型可以赋值给任意类型
void类型
没返回值
function sum(num1: number, num2: number):void {
console.log(num1 + num2)
}
sum(20, 30)
never类型
确保总是穷尽 了(message: string | number | boolean)
的可能类型,防止忘了添加逻辑处理
function handleMessage(message: string | number | boolean) {
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
}
}
tuple元组类型
- 元组中每个元素都有自己特性的类型,根据索引值获取到的值可以确定对应的类型
const info: [string, number, number] = ["gqb", 19, 1.75]
const name = info[0]
console.log(name.length)
函数参数及返回值
// 给参数加上类型注解: num1: number, num2: number
// 给返回值加上类型注释: (): number
// 在开发中,通常情况下可以不写返回值的类型(自动推导)
function sum(num1: number, num2: number) {
return num1 + num2
}
sum(123, 321)
匿名函数
const names = ["abc", "cba", "nba"]
// item根据上下文的环境推导出来的, 这个时候可以不添加的类型注解
// 上下文中的函数: 可以不添加类型注解
names.forEach(function(item) {
console.log(item.split(""))
})
对象&&可选类型
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)
}
}
类型别名
- 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
- 转换成更具体的类型
const el = document.getElementById("why") as HTMLImageElement
非空类型断言 !
function printMessageLength(message?: string) {
// if (message) {
// console.log(message.length)
// }
// vue3源码
console.log(message!.length)
}
可选链 ?.
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.friend?.girlFriend?.name)
!!
运算符
const message = "Hello World"
const flag = !!message
console.log(flag)//true
??
运算符
- Hello World 不存在的时候且为
null
时,就会赋值??
后面的值
let message: string|null = "Hello World"
const content = message ?? "你好啊, 大帅比"
// const content = message ? message: "你好啊, 大帅比"
console.log(content)
字面量类型
- 字面量类型的意义, 就是必须结合联合类型
type Alignment = 'left' | 'right' | 'center'
let align: Alignment = 'left'
align = 'right'
align = 'center'
type Method = 'GET' | 'POST'
function request(url: string, method: Method) {}
type Request = {
url: string,
method: Method
}
const options:Request = {
url: "https://www.coderwhy.org/abc",
method: "POST"
}
request(options.url, options.method)
类型缩小
-
typeof
结合if
语句 -
==
===
!==
switch
switch (direction) {
case 'left':
console.log(direction)
break;
case ...
}
-
instanceof
参数实例出处
class Student {
studying() {}
}
class Teacher {
teaching() {}
}
function work(p: Student | Teacher) {
if (p instanceof Student) {
p.studying()
} else {
p.teaching()
}
}
-
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)
函数类型
- 规定传入一个怎样函数,返回值类型
function calc(n1: number, n2: number, fn: (num1: number, num2: number) => number) {
return fn(n1, n2)
}
const result1 = calc(20, 30, function(a1, a2) {
return a1 + a2
})
console.log(result1)
const result2 = calc(20, 30, function(a1, a2) {
return a1 * a2
})
console.log(result2)
参数默认值
- 如果无值时,参数为undefined时,默认赋值是20,
// 必传参数 - 有默认值的参数 - 可选参数
function foo(y: number, x: number = 20) {
console.log(x, y)
}
foo(30)
函数的重载,不能使用联合类型解决的话就优先用联合类型
- 在函数的重载中, 实现函数是不能直接被调用的
add({name: "why"}, {age: 18})
会报错,只能是重载函数进行间接调用
image.png
抽象函数 abstract
- 抽象类的抽象方法必须被子类实现
接口
接口和类的区别
1、接口类似于类,但接口的成员都没有执行方式,它只是方法、属性、事件和索引的组合而已,并且也只能包含这四种成员;类除了这四种成员之外还可以有别的成员(如字段)。
2、不能实例化一个接口,接口只包括成员的签名;而类可以实例化(abstract类除外)。
3、接口没有构造函数,类有构造函数。
4、接口不能进行运算符的重载,类可以进行运算符重载。
5、接口的成员没有任何修饰符,其成员总是公共的,而类的成员则可以有修饰符(如:虚拟或者静态)。
interface CalcFn {
(n1: number, n2: number): number
}
function calc(num1: number, num2: number, calcFn: CalcFn) {
return calcFn(num1, num2)
}
const add: CalcFn = (num1, num2) => {
return num1 + num2
}
calc(20, 30, add)
枚举
- 定义一些常量,然后在其他地方使用
enum Direction {
LEFT = "LEFT",
RIGHT = "RIGHT",
TOP = "TOP",
BOTTOM = "BOTTOM"
}
泛型
- 类型的参数化
// 在定义这个函数时, 我不决定这些参数的类型
// 而是让调用者以参数的形式告知,我这里的函数参数应该是什么类型
function sum<Type>(num: Type): Type {
return num
}
// 1.调用方式一: 明确的传入类型
sum<number>(20)
sum<{name: string}>({name: "why"})
sum<any[]>(["abc"])
// 2.调用方式二: 类型推到
sum(50)
sum("abc")
模块化开发
模块开发的时候,要需要 declare
声明文件 .d.ts
文件
- 声明文件
// 声明模块
declare module 'lodash' {
export function join(arr: any[]): void
}
// 声明变量/函数/类
declare let whyName: string
declare let whyAge: number
declare let whyHeight: number
declare function whyFoo(): void
declare class Person {
name: string
age: number
constructor(name: string, age: number)
}
declare module '*.jpg'
declare module '*.jpeg'
declare module '*.png'
declare module '*.svg'
declare module '*.gif'
网友评论