ts不是在终端运行,是一门中间语言,最终编译为js运行。
// 1. ts编译为js
npm i -g typescript
// 查看版本
tsc -v
// 2. ts直接运行,主要用来查看是否报错
npm i -g ts-node
// 查看版本
ts-node -v
1.手动编译ts代码
tsc .\test.ts
2.生成tsconfig.json文件
tsc --init
# 生成package.json文件
npm init -y
# 安装webpack环境
npm i -D webpack webpack-cli
# 安装ts解析
npm i -D ts-loader
# 安装html模板
npm i -D html-webpack-plugin
# 安装webpack本地服务器
npm i -D webpack-dev-server
在根目录下编写webpack.config.js文件
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
mode: 'development',
entry: "./src/index.ts",
output: {
path: path.resolve(__dirname, "./dist"),
filename: "bundle.js"
},
resolve: {
extensions: [".ts", ".js", ".cjs", ".json"]
},
devServer: {},
module: {
rules: [
{
test: /\.ts$/,
loader: "ts-loader"
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
},
]
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html'
})
]
}
生成ts配置文件,tsconfig.json
tsc --init
声明的类型称为类型注解(Type Annotation)
let 类型推断为具体类型
const 类型推荐为字面量类型
非引用类型:
number、string、boolean、undefined、null、Symbol、BigInt
// 非引用类型:
// number、string、boolean、undefined、null、Symbol、BigInt
let num:number = 10
let num2:number = 0b110
let num3:number = NaN
let num4:number = Infinity
let flag:boolean = false
let str:string = '123'
let str2:string = "abc"
let unde:undefined = undefined
let nu:null = null
// 表示唯一,即使内容一样也表示唯一
let s1:symbol = Symbol('k1')
let s2:symbol = Symbol('k1')
let person = {
[k1]:'v1',
[k1]:'v2'
}
// 字面量类型
var ENV:"production"|"development"|"test"='development'
let age:99|100 = 99
引用类型:object、array、function
// 只能空数组
let arr1:[] = []
let arr2:number[] = [1,2,3]
let arr3:Array<number> = [1,2,3]
// 数组内有字符串和数字类型
var arr:(string|number)[] = ['cjc',999]
// 字符串数组或数字数组
var arr2: string[] | number[] = ['a', 'b']
var arr3: string[] | number[] = [1, 2]
// 元祖,顺序和类型都要满足
// 最后任意类型且可有可无
var arr4: [string, number, any?] = ['cjc', 999, true]
// 不定参数
var arr4: [string, number, ...(number|string)[]] = ['cjc', 999, 1,2,3]
// 空对象
let obj:object = {}
let obj2:{} = {name:'cjc'}
let obj3:{name:string,age:number} = {name:'cjc',age:999}
// 键名数字类型
var obj4: { [propNmae: number]: string } = { 1: 'a', 2: 'b' }
// 可选 ?
var obj5: { x: number, y?: boolean } = { x: 1 }
// 1.声明式函数定义
function sumFun(a: number, ...args: number[]): number {
return a + args.reduce((preVal: number, curVal: number) => {
return preVal + curVal
})
}
console.log(sumFun(1, 2, 3)); //6
// 2.函数变量
let foo2: (a: string) => string = function (a) {
return a
}
// 3.匿名函数
// 一般匿名函数不用指定类型
callback(function(){})
// this处理
function foo3(this:void,a:number){}
foo3(1)
方式1 函数类型表达式
// 定义函数的类型
// 必须携带形参名
type calcFnType = (num1: number, num2: number) => number
function calc(calcFn: calcFnType) {
let res = calcFn(1, 2)
return res
}
function add(a: number, b: number) {
return a + b
}
function minus(a: number, b: number) {
return a - b
}
let res = calc(add)
// 3
console.log(res);
let res2 = calc(minus)
// -1
console.log(res2);
方式2 调用签名(call signatures)
函数本身也是对象类型,可以给函数指定类型的同时添加属性
interface IFoo {
name: string,
age: number,
(num: number): number
}
const foo: IFoo = (num: number): number => {
return 1
}
foo.name = 'ccc'
foo.age = 999
函数重载:函数名相同,形参不同
//输入数字 `123` 的时候,输出反转的数字 `321`,输入字符串 `'hello'` 的时候,输出反转的字符串 `'olleh'`
// 1.函数重载签名
function reverse(x: number): number;
function reverse(x: string): string;
// 2.通用函数实现
function reverse(x: any): any {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
any、unknow都能赋值任何类型的值
any类型能进行任何操作
unknow类型不能进行任何操作,类型缩小(例如typeof)后才能进行对应类型的操作
// 1.any
let a: any = 123
let b: string = a
// 2.unknow
// unknow比any更安全,unknow类型只能赋值给unknow或any
let a2: unknown = 123
//不能将类型“unknown”分配给类型“string”
// let b2:string = a2
let b2: any = a2
函数没有返回值时,返回void类型
type execFunType = (...args: any[]) => void
function delayFun(fn: execFunType) {
setTimeout(() => {
fn('ccc', 999)
}, 1000);
}
delayFun((name, age) => {
console.log(name);
console.log(age);
})
never类型不能有任何值
应用场景:
没有对boolean类型的处理,报错:
增加对boolean的处理:
function foo(msg: string | number | boolean) {
switch (typeof msg) {
case 'string':
console.log(msg.length);
break;
case "number":
console.log(msg);
break;
case "boolean":
break;
default:
const check: never = msg
break;
}
}
一般数组中存放相同的数据类型,元祖中可以存放不同的数据类型
const stu:[string,number] = ['CCC',999]
const name = stu[2]
应用场景:用于函数的返回值
function useState<T>(state: T): [T, (newState: T) => void] {
let currentState = state
const changeState = (newState: T) => {
currentState = newState
}
return [currentState, changeState]
}
//const counter: number
//const setState: (newState: number) => void
const [counter, setState] = useState(10)
// 10
console.log(counter);
type起别名,常用于非对象类型
// 非对象类型
type idType = number | string
let id1:idType = 1
let id2:idType = '1'
// 对象类型
type pointType = {x:number,y:number,z?:number}
let point:pointType = {1,2,3}
interface 只能声明对象类型
多次声明同一个接口名称:
interface pointType {
x: number,
y: number
}
interface pointType {
z?: number
}
const p1: pointType = {
x: 1,
y: 2,
}
const p2: pointType = {
x: 1,
y: 2,
z: 3
}
//{ x: 1, y: 2 } object
console.log(p1, typeof p1);
//{ x: 1, y: 2, z: 3 } object
console.log(p2, typeof p2);
接口继承:能多继承
interface IPerson {
name: string,
age: number
}
interface IAnimal {
sleep?: string,
}
interface IStu extends IPerson,IAnimal {
sno: number | string
}
const s1: IStu = {
name: 'ccc',
age: 999,
sno: 1
}
// 定义对象接口
interface Person {
// 1.只读属性
readonly id: number,
name: string,
age: number,
// 2.可选属性
gender?: string,
// 3.动态属性名
[attrName: string]: any
}
let p1: Person = {
id: 1,
name: 'cjc',
age: 999,
song: 'jinitaimei'
}
interface person {
age: number,
eat(food: string): string
}
// 类实现接口
// 能同时实现多个接口
class stu implements person {
age: number
eat(food: string): string
eat(food: string) {
return 'apple'
}
}
// 函数接口
interface Ifun{
// (形参名1:类型1,形参名2:类型2):返回值类型
(a:string,b:string):boolean
}
const func1:Ifun = function(a:string,b:string):boolean{
return a.search(b) !== -1
}
数组(可索引类型)
// 数组的接口
interface IArray{
// 属性名为number类型(即数组下标为number)
// 属性值为任意类型any
[index:number]:any
}
let arr5:IArray = [1,2,'a',true]
联合类型
const a:number|string|boolean = true
交叉类型
interface IPerson {
name: string,
age: number
}
interface IStu extends IPerson {
name: string
study: () => void
}
// 交叉类型 &
type StuType = IPerson & IStu
const s1: StuType = {
name: 'ccc',
age: 999,
study() {
console.log(1);
}
}
当TS没法获取某个确定类型时,使用类型断言(Type Assertions)
// let div: HTMLDivElement | null
let div = document.querySelector('div')
// 当用类获取元素时,TS无法推断是什么类型
// let box1: Element | null
let box1 = document.querySelector('.box')
// let box2: HTMLDivElement
let box2 = document.querySelector('.box') as HTMLDivElement
断言能断言成更具体的类型或不太具体的类型
// const age: number
const age: number = 99
// const age2: any
const age2 = age as any
// const age3: string
const age3 = age2 as string
非空断言
interface IPerson {
name: string,
age: number,
hobbies?: string[]
}
const p1: IPerson = {
name: 'ccc',
age: 999,
hobbies: ['a']
}
// 访问属性 可选连 ?
console.log('设置之后:', p1.hobbies?.[0]);
// 设置属性
// 方式1 类型缩小
if (p1.hobbies) {
p1.hobbies[0] = 'rap'
}
// 方式2 非空类型断言
p1.hobbies![0] = 'rap'
console.log('设置之后:', p1.hobbies?.[0]);
function request(url: string, method: "get" | "post") { }
const info1 = {
url: 'xxx',
method: "get"
}
// info1中method的类型为string
// 方式1 断言为get
request(info1.url, info1.method as "get")
// 方式2 将info对象类型断言为字面量类型
// 字面量推理
// const info2: { url: string, method: "get" | "post" } = {
// url: "xxx",
// method: "get"
// }
const info2 = {
url: "xxx",
method: "get"
} as const
request(info2.url, info2.method)
===
、!==
==
!=
常用于字面量类型的判断class Person {
public name
public age
constructor(name: string, age: number) {
this.name = name
this.age = age
}
}
// 以上代码的语法糖形式:
class Person2 {
constructor(public name: string, public age: number) { }
}
成员修饰符
属性修饰符
class Person {
// 约定俗成,私有属性 _表示
constructor(private _name: string) {}
set name(newVal: string) {
console.log('设置私有属性_name:');
this._name = newVal
}
get name() {
console.log('获取私有属性_name:');
return this._name
}
}
let p1 = new Person('ccc')
console.log(p1.name);
p1.name = 'CJC'
console.log(p1.name);
//打印结果:
//获取私有属性_name:
//ccc
//设置私有属性_name:
//获取私有属性_name:
//CJC
interface ICollection {
[index: number]: any
length: number
}
function printCollection(collection: ICollection) {
for (let i = 0; i < collection.length; i++) {
console.log(collection[i]);
}
}
const arr = [1, 2, 3]
printCollection(arr)
const str = 'abc'
printCollection(str)
enum nums {
one = 1,
two,
three
}
// 从1开始递增
// 3
console.log(nums.three);
// 通过名称拿到值
// 也能从值拿到名称
// { '1': 'one', '2': 'two', '3': 'three', one: 1, two: 2, three: 3 }
console.log(nums);
function foo<T, E>(a: T, b: E) { }
// 1.自动类型推断
foo(1, { name: 'ccc', age: 999 })
// 2. 类型注解
foo<number, { name: string, age: number }>(1, { name: 'ccc', age: 999 })
例:传入的类型必须有length属性
interface ILength {
length: number
}
function getLength<T extends ILength>(args: T) {
return args.length
}
console.log('arr:', getLength([1, 2, 3]));
console.log('str:', getLength("abc"));
例:根据对象的键(不管是否存在),获取对象的值
// function getProperty(obj: any, key: any): any
function getProperty(obj, key) {
return obj[key]
}
const p = {
name: 'ccc',
age: 99
}
// ccc
console.log(getProperty(p, "name"));
// 若没有类型约束,可以传入p中不存在的键
// undefined
console.log(getProperty(p, "gender"));
例:根据对象的键(只能获取对象p中存在的键),获取对象的值
keyof 获取p中所有的键组成的联合类型,如string|nunmber
// function getProperty(obj: O, key: K): O[K]
function getProperty<O, K extends keyof O>(obj: O, key: K) {
return obj[key]
}
const p = {
name: 'ccc',
age: 99
}
// ccc
console.log(getProperty(p, "name"));
// 类型“"gender"”的参数不能赋给类型“"name" | "age"”的参数
// console.log(getProperty(p, "gender"));
interface IPerson {
name: string
age: number
}
type MapType<T> = {
// 拷贝传入类型T的所有键值对
[key in keyof T]: T[key]
}
type NewPerson = MapType<IPerson>
let p1: NewPerson = { name: 'ccc', age: 999 }
例子:将所有类型转为必填
interface IPerson {
name: string
age?: number
readonly gender: string
}
type mapType<T> = {
// 拷贝传入类型T的所有键值对
// - 去除修饰符
-readonly [key in keyof T]-?: T[key]
}
type NewPerson = mapType<IPerson>
let p1: NewPerson = { name: 'ccc', age: 999, gender: 'male' }
没有export的js或ts文件会被认为是脚本。脚本中声明的变量和类型等在全局作用域中。
将脚本变为模块 export {} (即使没有导出任何内容)
xxx.d.ts称为类型声明文件(Type Declaration)或类型定义文件(Type Definition)
npm i react
npm i -S @types/react
自定义类型声明文件 xxx.d.ts
// 声明变量类型
declare const name:string
declare const age:number
// 声明函数类型
declare function foo(a:number):number
// 声明类的类型
declare class Person {
constructor(public name:string,public age:number)
}
// 声明模块
// 假设lodash没有类型库
declare module "lodash" {
export function join(args: any[]):string;
}
// 声明命名空间
// jQuery等使用CDN方式使用时(不是引入模块的方式)
declare namespace $ {
export function ajax(setting:any):any
}
例:ts中导入图片文件,报错。需要声明文件模块
在类型声明文件中:
declare module "*.avif"