1.安装typescript编译器
npm i -g typescript
安装之后使用tsc运行ts文件,然后会编译出对应的js文件,再通过node运行js文件,就能获得打印内容。
ts定义内容
function fn(people, date) {
console.log(`hello${people},today is ${date}`);
}
fn("张三", "2023.2.15")
编译内容
function fn(people, date) {
console.log("hello".concat(people, ",today is ").concat(date));
}
fn("张三", "2023.2.15");
但是会发现ts提示函数重复声明,这是因为ts和编译后的js文件函数名一样,造成的问题。
如何解决?,可以通过tsc --init来生成一个配置文件解决冲突问题,但是会报两个any类型错误,此时在配置文件将 "strict": true,注释就行了,ts每次编译需要手动输入指令,如何自动编译,可以通过tsc --watch解决。
ts报了错,编译以后js还是正常运行的,如果想优化编译,可以在优化的时候加一个tsc --noEmitOnError这样的一个参数,如果ts出现一些类型错误,就不让编译js文件了。
2.降级编译
ts文件
function fn(people, date) {
console.log(`hello${people},today is ${date}`);
}
fn("1236", "2023.2.15")
编译的js文件
function fn(people, date) {
console.log(`hello${people},today is ${date}`);
}
fn("1236", "2023.2.15");
编译后的js文件中的模板字符串并没有被编译,这是因为语法不适应低版本浏览器,此时,在配置文件将"target": "es2016",改成"target": "es5"进行编译就行了。
function fn(people, date) {
console.log("hello".concat(people, ",today is ").concat(date));
}
fn("1236", "2023.2.15");
3.配置严格模式
配置文件配置以下属性,都可以开启严格模式,三者有所不同
"strict":true,
"noImplicitAny":true,
"strictNullChecks":true
4.类型定义
//基元类型 还有any,对象,函数等类型
let str: string = "hello"
let num: number = 20
let boolean: boolean = true
//数组的定义方法
let arr: number[] = [1, 2, 3]
//泛型
let arr2: Array<number> = [4, 5, 6]
//?表示可传可不传,最终pt.y打印undefind
function printcorrd(pt: { x: number, y?: number }) {
// console.log("x的坐标" + pt.x, "y的坐标" + pt.y);
// if (pt.y !== undefined) {
// console.log("y的坐标" + pt.y);
// }
}
printcorrd({ x: 20, y: 40 })
//联合类型,传一个值,参数是是其中任意类型即可
function fn(num: string | Number) {
// console.log("num的值是" + num);
if (typeof num === "string") {
console.log(num);
} else {
console.log(num);
}
}
fn(10)
fn("num")
5.类型定义别名
//类型别名 type进行类型别名的定义
type point = {
x: number
y: string
}
function fn(po: point) {
console.log(po.x);
}
fn({
x: 20,
y: "wer"
})
6.接口
//interface关键字创建接口
interface point {
x: number
y: number
}
function fn(pt: point) {
}
fn({
x: 20,
y: 30
})
//扩展接口
interface school {
name: string
}
interface person extends school {
pencil: boolean
}
const pe: person = {
name: "ls",
pencil: true
}
console.log(pe.name);
console.log(pe.pencil);
7.断言
//断言as或<>
const mydiv = document.getElementById("main_div") as HTMLDivElement
const mydiv2 = <HTMLDivElement>document.getElementById("main_div")
// const x = "hello" as number //报错
const x = ("hello" as any) as number
8.symbol和bigint
const a: bigint = BigInt(100)
const b: bigint = 100n
//实际两个值是不等的,会报错两者没有重叠
const first = Symbol("age")
const second = Symbol("age")
if (first === second) {
console.log('111');
}
9.类型缩小与真值缩小
//类型缩小就是从宽类型转化为窄类型的过程
//typeof 类型守卫
function pad(str: string | string[] | null) {
//加上str &&自动类型转换,如果传入的是有效的str
if (str && typeof str === "object") {
for (const s of str) {
console.log(s);
}
} else if (typeof str === "string") {
console.log(str);
} else {
}
}
function all(value: number[] | undefined, value2: number) {
if (!value) {
return value
} else {
return value.map(item => {
return item *= value2
})
}
}
console.log(all([1, 2], 3));//[3,6]
console.log(all(undefined, 3))//undefined
10.等值缩小,in操作符缩小,instanceof操作符缩小,分配缩小
function example(x: string | number, y: string | boolean) {
// x.toUpperCase()
// y.toLowerCase()
//以上两个会报错,因为不一定是字符串
//等值缩小,两值相等就只能是字符串
if (x === y) {
x.toUpperCase()
y.toLowerCase()
} else {
console.log(x, y);
}
}
example(122, true)
//in操作符缩小
type Fish = { swim: () => void }
type Bird = { flay: () => void }
//此时定义一个属性,并将其加入到函数中
type Human = { swim?: () => void, flay?: () => void }
function move(animal: Fish | Bird | Human) {
if ("swim" in animal) {
//animal可能是Fish|Human,此时使用断言
return (animal as Fish).swim()
}
//可能是Bird|Human
return (animal as Bird).flay()
}
//instanceof缩小
function value(x: Date | string) {
if (x instanceof Date) {
console.log(x.toUTCString());
} else {
console.log(x.toUpperCase());
}
}
value(new Date())
value("hello ts")
//分配缩小
// let x:string|number
let x = Math.random() < 0.5 ? 1 : "hello ts"
//let x:number
x = 1
console.log(x);
//let x:string
x = "sayHello"
console.log(x);
11.类型谓词
type Fish = {
name: string
swim: () => void
}
type Bird = {
name: string
fly: () => void
}
//pet is Fish类型谓词
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined
}
function getPet(): Fish | Bird {
let fish: Fish = {
name: "bear",
swim: () => {
}
}
let bird: Bird = {
name: "pan",
fly: () => { }
}
return true ? bird : fish
}
let pet = getPet()
if (isFish(pet)) {
pet.swim()
} else {
pet.fly()
}
const zoo: (Fish | Bird)[] = [getPet(), getPet(), getPet()]
const under: Fish[] = zoo.filter(isFish)
const under2: Fish[] = zoo.filter(isFish) as Fish[]
const under3: Fish[] = zoo.filter((pet): pet is Fish => {
if (pet.name === "frog") {
return false
}
return isFish(pet)
})
12.函数类型表达式
//函数表达式 fn:(a: string) => void void表示没有返回值
function blue(fn: (a: string) => void) {
fn("hello")
}
function current(s: string) {
console.log(s);
}
blue(current)
//以上写法可以换一种写法
type greet=(a:string)=>void
function blue(fn:greet) {
fn("hello")
}
function current(s: string) {
console.log(s);
}
blue(current)
13.调用签名和构造签名
//调用签名 (someArg: number)
type DescribableFunction = {
description: string
(someArg: number): boolean
}
function doSomething(fn: DescribableFunction) {
console.log(fn.description + "returned" + fn(6));
}
function fn1(n: number) {
console.log(n);
return true
}
fn1.description = "hello"
doSomething(fn1)
//构造签名
class Ctor {
s: string
constructor(s: string) {
this.s = s
}
}
type SomeConstructor = {
new(s: string): Ctor
}
function fn(ctor: SomeConstructor) {
return new ctor("hello")
}
const f = fn(Ctor)
console.log(f.s);
14.泛型--类型推断,泛型--使用受限值,泛型--指定类型参数
// function firstElement(arr:any[]){
// return 100
// }
// 泛型<Type>
function firstElement<Type>(arr: Type[]): Type | undefined {
return arr[0];
}
firstElement(["A"])
// <number>可写可不写,ts会进行推断,写了就不能写其他类型
firstElement<number>([1, 2, 3])
firstElement([])
//泛型<Input, Output>类型推断
function map<Input, Output>(arr: Input[], func: (arg: Input) => Output): Output[] {
return arr.map(func)
}
const parsed = map(["A", "B"], (n) => parseInt(n))
//泛型--使用受限值
//此时会报错,提示类型Type上不存在length,然后通过关键字extends,强制定义length为number就可以了
function len<Type extends { length: number }>(a: Type, b: Type) {
if (a.length >= b.length) {
return a
} else {
return b
}
}
const result=len([1,2],[3,5])
const res=len("as","bg")
const not=len(10,20)//报错,数字没有长度
//指定类型参数
function combie<Type>(arr1: Type[], arr2: Type[]): Type[] {
return arr1.concat(arr2)
}
const arr = combie([1, 2, 3], [4, 6])
const arr3 = combie(["1", "2"], ["A"])
//以下会报错,因为ts解析中认为是number,所以后面的string就会报错,如果要解决加一个<string|number>就可以了,表示传入的是string或number
const arr4 = combie<string | number>([1, 2, 3], ["A", "B"])
console.log(arr4);
15.泛型函数编写准测
// 编写函数的通用准则
//1.可能的情况下使用参数本身,而不是进行约束,尽可能采用第一种写法
function first<Type>(arr: Type[]) {
return arr[0]
}
function secend<Type extends any[]>(arr: Type) {
return arr[0]
}
const a = first([1, 2, 3])
const b = secend([1, 2, 3])
//2.总是尽可能少地使用类型参数
function filter1<Type>(arr: Type[], fun: (arg: Type) => boolean) {
return arr.filter(fun)
}
function filter2<Type, fun extends (arg: Type) => boolean>(arr: Type[],
fun: fun) {
return arr.filter(fun)
}
//3.如果一个类型的参数只出现在一个地方,请考虑你是否真的需要他
function greet(s: string) {
console.log("hello" + s);
}
greet("world")
//很明显将str约束为string没什么必要
function greet2<str extends string>(s: str) {
console.log("hello" + s);
}
greet2("hi")
16.函数及回调中的可选参数
//让number有一个100的初始值,此时n不能在赋?
function fn(n: number = 100) {
console.log(n.toFixed());
console.log(n.toFixed(3));
}
fn(123.45)
fn()
//回调中的可选参数
//当为回调写一个函数类型时,永远不要写一个可选参数,除非你打算在不传递该参数的情况下调用函数
function myForeach(arr: any[], callback: (arg: any, index?: number) => void) {
for (var i = 0; i < arr.length; i++) {
callback(arr[i], i)
}
}
myForeach([1, 2, 3], (a) => console.log(a))
myForeach([1, 5, 3], (a, i) => console.log(a, i))
function myForeach(arr: any[], callback: (arg: any, index?: number) => void) {
for (var i = 0; i < arr.length; i++) {
//此时默认不写index
callback(arr[i])
}
}
myForeach([1, 5, 3], (a, i) => {
console.log(i.toFixed());//会报错
})