npm i -s typescript
npx tsc --init
生成tsconfig.json文件npx tsc xxx.ts
npx tsc --watch
npx tsc --noEmitOnError --watch
node xx.js
执行对应文件let str:string= 'hello typescript'
let num:number = 100
let bool:boolean = true
let arr:number[] = [1,2,3]
// arr = ['a']
let arr2:Array<number> = [1,2,3]
// arr2=['a']
let obj:any={
x:0
}
// let obj={
// x:0
// }
// obj.foo()
// obj()
// obj.bar = 100
// obj = 'hello'
// const n:number = obj
// let myName:string = 'Felixlu'
// int x = 0
let myName = 'Felixlu'
// myName = 100
function greet(name:string){
console.log("Hello," + name.toUpperCase() + "!!")
}
greet('aa')
function getFavoriteNumber():number{
return 26
}
const names = ['小前','小封','小圆']
names.forEach(function(s) {
console.log(s.toUpperCase())
})
names.forEach((s)=> {
console.log(s.toUpperCase)
})
function printCoord(pt:{x:number;y:number}){
console.log("x:" + pt.x)
console.log("y:" + pt.y)
}
printCoord({x:3, y:7})
function printName(obj: {first:string, last?: string}){
// console.log(obj.last?.toUpperCase())
// if(obj.last != undefined){
// console.log(obj.last.toLowerCase())
// }
// ?解决last是undefined的问题
console.log(obj.last?.toUpperCase())
}
// printName({
// first:'Felix'
// })
// printName({
// first:'Felix',
// last:'Lu'
// })
printName({
first:'Felix',
last:undefined
})
function printId7(id:number | string){
// console.log('Your ID is:' +id)
// console.log(id.toUpperCase())
if(typeof id === 'string'){
console.log(id.toUpperCase())
}else{
console.log(id)
}
}
printId7(101)
printId7('202')
// printId7(true)
function welcomPeople(x:string[] | string){
if(Array.isArray(x)){
console.log('Hello,' + x.join('and'))
}else{
console.log('Welcome lone traveler' + x)
}
}
welcomPeople('A')
welcomPeople(['a','b'])
function getFirstThree(x:number[] | string): number[] | string {
return x.slice(0,3)
}
console.log(getFirstThree('abcdefg'))
console.log(getFirstThree([2,3,4,5,6]))
type Point = {
x:number
y:number
}
function printCoord8(pt:Point) {
}
printCoord8({x:100,y:200})
type ID = number | string
function printId8(id:ID){
}
printId8(100)
printId8('10')
type UserInputSanitizedString = string
function sanitizedInput(str:string): UserInputSanitizedString {
return str.slice(0,2)
}
let userInput = sanitizedInput('hello')
console.log(userInput)
userInput = 'new Input'
一种结构类型,定义对象类型的另外一种方式 用关键字interface来定义
interface Point9{
x:number;
y:number;
}
function printCoord9(pt:Point9){
console.log("坐标x的值是:"+pt.x)
console.log("坐标y的值是:"+pt.y)
}
printCoord9({x:100,y:100})
// 扩展接口
/* interface Animal{
name:string
}
interface Bear extends Animal{
honey:boolean
}
const bear:Bear = {
name:'winie',
honey: true
}
console.log(bear.name)
console.log(bear.honey) */
/* type Animal = {
name:string
}
type Bear = Animal & {
honey:boolean
}
const bear:Bear = {
name:'winnie',
honey:true
} */
// 向现有的类型添加字段
/* interface MyWindow {
count:number
}
interface MyWindow {
title:string
}
const w: MyWindow = {
title:'hello ts',
count:100
} */
// 类型type创建后不能更改, interface可新增
/* type MyWindow = {
title:string
}
type MyWindow = {
count:string
} */
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement
const myCanvas2 = <HTMLCanvasElement>document.getElementById("main_canvas")
const x = ('hello' as any) as number
const y = ('hello' as unknown) as number
let b2:false = false
const obj11 = {
count:0
}
if(true){
obj11.count = 1
}
function handleRequest(url:string, method: 'GET'|'POST'|'GUESS'){}
/* const req = {
url:'https://example.com',
method:'GET' // 1 method:'GET' as 'GET'
}
// handleRequest(req.url, req.method) // Argument of type 'string' is not assignable to parameter of type '"GET" | "POST" | "GUESS"'
handleRequest(req.url, req.method as 'GET') // 2 */
const req = {
url:'https://example.com',
method:'GET'
} as const // 3
// handleRequest(req.url, req.method) // Argument of type 'string' is not assignable to parameter of type '"GET" | "POST" | "GUESS"'
handleRequest(req.url, req.method) // 2
null 不存在
undefined 未初始化的值
let x12:undefined = undefined
let y12:null = null
// let z12:string = undefined // Type 'undefined' is not assignable to type 'string'. // 可将tsconfig.josn文件"strictNullChecks"改为false,就可行
function doSomething(x:string | null){
if(x=== null){
// 做一些事情
}else {
console.log('Hello,' + x.toUpperCase())
}
}
function liveDangerously(x?:number | null){
// !断言为你能肯定这个值不是null或者undefined
console.log(x!.toFixed())
}
enum Direction{
Up = 1,
Down,
Left,
Right,
}
console.log(Direction.Up) // 1
bigint 非常大的整数
symbol 全局唯一引用
// BigInt literals are not available when targeting lower than ES2020. 修改"target": "es2020",
const oneHundred: bigint = BigInt(100)
const anotherHundred: bigint = 100n
const firstName = Symbol("name")
const secondName = Symbol("name")
// This comparison appears to be unintentional because the types 'typeof firstName' and 'typeof secondName' have no overlap.
// if(firstName === secondName){
// console.log('ok')
// }
宽类型转为窄类型过程,常用于处理联合类型变量的场景
function padLeft(padding:number | string, input: string): string {
<!-- throw new Error("尚未实现!") -->
return new Array(padding + 1).join(" ") + input
}
function padLeft(padding:number | string, input: string){
if(typeof padding === "number"){
return new Array(padding + 1).join(" ") + input
}
return padding + input
}
function printAll(strs:string | string[] | null){
// 'strs' is possibly 'null' 因为typeof null == object
if(typeof strs === 'object'){
// for(const s of strs){
// console.log(s)
// }
}else if(typeof strs === 'string'){
console.log(strs)
} else {
// ...
}
}
typeof strs === “object” // “string”、“number”,“bigint”,“boolean”,“symbol”,“undefined”,“function”
function printAll2(strs:string | string[] | null){
// 'strs' is possibly 'null' 因为typeof null == object
/* if(strs && typeof strs === 'object'){
for(const s of strs){
console.log(s)
}
}else if(typeof strs === 'string'){
console.log(strs)
} else {
// ...
} */
if(strs){
if(typeof strs === 'object'){
for(const s of strs){
console.log(s)
}
}else if(typeof strs === 'string'){
console.log(strs)
} else {
// ...
}
}
}
function multiplyAll(
values:number[] | undefined,
factor:number
){
if(!values){
return values
}else{
return values.map((x) => {
return x*factor
})
}
}
console.log(multiplyAll([3,4],2))
console.log(multiplyAll(undefined,2))
multiplyAll([3,4],2)
条件、&&、||、if语句、布尔否定( !)
function getUsersOnlineMessage (numUsersOnline:number){
if(numUsersOnline){
return 现在共有 ${numUsersOnline} 人在线!
}
return “现在没有人在线. ”
}
Boolean(“hello”) // type:boolean,value:true
!!“world” // type:true, value:true
=== , !==, ==, !=
function example3(x:string | number, y: string | boolean){
// x.toUpperCase() // Property 'toUpperCase' does not exist on type 'string | number'.
// y.toUpperCase()
if(x===y){
x.toUpperCase()
y.toUpperCase()
}else{
console.log(x)
console.log(y)
}
}
function printAll3(strs:string | string[] | null){
if(strs !== null){
if(typeof strs === 'object'){
for(const s of strs){
console.log(s)
}
}else if(typeof strs === 'string'){
console.log(strs)
} else {
// ...
}
}
}
interface Container {
value: number | null | undefined
}
function multiplyValue(container: Container, factor: number) {
if(container.value != null){
console.log(container.value)
container.value *= factor
}
}
multiplyValue({value:5},6)
multiplyValue({value:undefined},6)
multiplyValue({value:null},6)
// multiplyValue({value:'5'},6)
value in x
type Fish = { swim: () => void}
type Bird = { fly: () => void}
type Human = { swim?: () => void; fly?: () => void}
// function move (animal: Fish | Bird){
// if('swim' in animal){
// return animal.swim()
// }
// return animal.fly()
// }
function move (animal: Fish | Bird | Human){
// Cannot invoke an object which is possibly 'undefined'.
if('swim' in animal){
// return animal.swim()
return (animal as Fish).swim()
}
// return animal.fly()
return (animal as Bird).fly()
}
x instanceof Foo
x的原型链上是否含有Foo.prototype
function logValue(x:Date | string){
if(x instanceof Date){
console.log(x.toUTCString())
}else{
console.log(x.toUpperCase())
}
}
logValue(new Date())
logValue('hello ts')
// let x: string | number
let x = Math.random() < 0.5 ? 10 : “hello world!”
// let x: string | number
let x6 = Math.random() < 0.5 ? 10 : "hello world!"
// let x6 : number
x6 = 1
console.log(x6)
// let x6 = string
x6 = 'goodbye!'
console.log(x6)
// let x6: boolean
// x6 = true // Type 'boolean' is not assignable to type 'string | number'.
function padLeft(padding:number | string, input:string){
if(typeof padding === “number”){
return new Array(padding + 1).join(" ") + input
}
return padding + input
}
function example7(){
let x: string | number | boolean
x = Math.random() < 0.5
// let x: boolean
console.log(x)
if(Math.random() < 0.5){
x = 'hello'
// x:string
console.log(x)
}else{
x = 100
// x: number
console.log(x)
}
// x变成了string|number,boolean被覆盖了
return x
}
let x = example7()
x = 'hello'
x = 100
// 不能将类型“boolean”分配给类型“string | number”
// x = true
直接控制整改代码的类型变化,定义一个用户定义的类型保护,直接定义一个函数,让它返回值是一个类型谓词就好了
function isFish(pet: Fish | Bird): pet is Fish{
return (pet as Fish).swim !== undefined
}
返回值: pet is Fish 类型谓词
type Fish8 = {
name: string
swim: () => void
}
type Bird8 = {
name:string
fly:() => void
}
function isFish(pet: Fish8 | Bird8): pet is Fish8{
return (pet as Fish8).swim !== undefined
}
function getSmallPet(): Fish8 | Bird8 {
let fish: Fish8 = {
name: 'sharkey',
swim:()=> {
}
}
let bird: Bird8 = {
name:'sparrow',
fly: ()=> {
}
}
return true ? bird : fish
}
let pet = getSmallPet()
if(isFish(pet)){
pet.swim()
}else{
pet.fly()
}
const zoo: (Fish8 | Bird8)[] = [getSmallPet(), getSmallPet(), getSmallPet()]
const underWater1: Fish[] = zoo.filter(isFish)
const underWater2: Fish[] = zoo.filter(isFish) as Fish[]
const underWater3: Fish[] = zoo.filter((pet): pet is Fish8 => {
if(pet.name === 'frog'){
return false
}
return isFish(pet)
})
联合类型出现的问题以及解决
interface Shape {
kind: “circle” | “square”
radius?: number
sideLength?:number
}
// interface Shape {
// kind: "circle" | "square"
// radius?: number
// sideLength?:number
// }
interface Circle {
kind:'circle'
radius: number
}
interface Square {
kind:'square'
sideLength: number
}
type Shape = Circle | Square
/* function handleShape(shape:Shape) {
if(shape.kind === 'rect'){
}
} */
/* function getArea(shape:Shape){
if(shape.kind === 'circle'){
return Math.PI * shape.radius! ** 2
}
} */
function getArea(shape:Shape){
switch(shape.kind){
case 'circle':
return Math.PI * shape.radius ** 2
case 'square':
return shape.sideLength ** 2
}
}
never:不应该存在的状态
interface Circle {
kind:'circle'
radius: number
}
interface Square {
kind:'square'
sideLength: number
}
interface Triangle {
kind:'triangle'
sideLength: number
}
type Shape10 = Circle | Square | Triangle
function getArea10(shape:Shape10){
switch(shape.kind){
case 'circle':
return Math.PI * shape.radius ** 2
case 'square':
return shape.sideLength ** 2
default:
// 不能将类型“Triangle”分配给类型“never”,除非再加一个 case ‘Triangle’
const _exhaustiveCheck: never = shape
return _exhaustiveCheck
}
}
fn: (a:string) => void
type GreetFunction = (a:string) => void
function greeter(fn: GreetFunction){
fn('Hello')
}
function printToConsole(s:string){
console.log(s)
}
greeter(printToConsole)
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) // 6 'hello returned true'
// 参数s,返回对象Ctor,new构造签名
// class Ctor {
// s:string
// constructor(s:string){
// this.s = s
// }
// }
// /* type SomeConstructor = {
// (s:string):Ctor
// }
// function fn(ctor: SomeConstructor){
// ctor('hello')
// } */
// type SomeConstructor = {
// new (s:string):Ctor
// }
// function fn(ctor: SomeConstructor){
// return new ctor('hello')
// }
// const f = fn(Ctor)
// console.log(f.s)
// 调用签名和构造签名
interface CallOrConstructor {
new (s:string):Date
(n?: number):number
}
function fn(date:CallOrConstructor){
let d = new date('2021-12-20')
let n = date(100)
}
两个值之间存在对应关系
function firstElement(arr: any[]){
return arr[0]
}
// 标识符 入参为标识符Type类型 返回值类型也是Type
function firstElement<Type>(arr:Type[]):Type | undefined{
return arr[0]
}
const s = firstElement(["a",'b','c']) // s是'string'类型
const n = firstElement([1,2,3]) // n是'number'类型
const u = firstElement([]) // n是undefined类型
/* function firstElement(arr: any[]){
// 返回值return决定,arr由any值组成的数组
// return arr[0] // 返回any
return 100 // 返回number
}
const s = firstElement(["a",'b','c']) */
// 让输入和输出类型保持一致
function firstElement<Type>(arr: Type[]): Type | undefined{
return arr[0]
// return 100
}
firstElement(['a','b','c'])
firstElement([1,2,3])
firstElement([])
firstElement<string>(['a','b','c'])
firstElement<number>([1,2,3])
firstElement<undefined>([])
function map<Input,Output>(arr: Input[], func:(arg: Input) => Output): Output[]{
return arr.map(func)
}
const parsed = map(['1','2','3'], (n)=> parseInt(n))
console.log(parsed) // [ 1, 2, 3 ]
约束条件限制一个类型参数可以接受的类型
为了保证Type一定有一个length类型,所以加一个限制条件,给这个泛型后面加关键字extends { length: number}
function longest<Type extends { length: number}>(a: Type, b: Type){
if(a.length >= b.length){
return a
}else{
return b
}
}
/* function longest(a: Type, b: Type){
// Property 'length' does not exist on type 'Type'
if(a.length >= b.length){
return a
}else{
return b
}
} */
function longest<Type extends { length: number}>(a: Type, b: Type){
if(a.length >= b.length){
return a
}else{
return b
}
}
const longerArray = longest([1,2],[1,2,3])
const longerString = longest('fleee','ss')
// extends { length: number}是限制条件而不是扩展条件
// const notOk = longest(10,100) // Argument of type 'number' is not assignable to parameter of type '{ length: number; }'.
function minimumLength<Type extends {length:number}>(obj:Type,minimum:number):Type{
if(obj.length >= minimum){
return obj
}else{
return {length:minimum}
}
}
function minimumLength<Type extends {length:number}>(
obj:Type,
minimum:number
):Type{
if(obj.length >= minimum){
return obj
}else{
return {length:minimum} // 不能将类型“{ length: number; }”分配给类型“Type”。"{ length: number; }" 可赋给 "Type" 类型的约束,但可以使用约束 "{ length: number; }" 的其他子类型实例化 "Type"。
}
}
const arr = minimumLength([1,2,3], 6)
console.log(arr.slice(0))
const arr = combine
function combine<Type>(arr1: Type[], arr2: Type[]): Type[]{
return arr1.concat(arr2)
}
// const arr = combine([1,2,3],[4,5])
// ts会自动推断type类型
// const arr = combine([1,2,3],['asss','5']) //Type 'string' is not assignable to type 'number'.
// 指定type类型为string或者number
const arr = combine<string | number>([1,2,3],['asss','5'])
console.log(arr)
// 1. 可能的情况下,使用类型参数本身,而不是对其进行约束
function firstElement1<Type>(arr: Type[]){
return arr[0]
}
function firstElement2<Type extends any[]>(arr: Type){
return arr[0]
}
const a = firstElement1([1,2,3])
const b = firstElement2([1,2,3])
// 2. 总是尽可能少地使用类型参数
function filter1<Type>(arr: Type[], func:(arg:Type) => boolean){
return arr.filter(func)
}
function filter2<Type,Func extends(arg:Type)=>boolean>(
arr:Type[],
func:Func
){
return arr.filter(func)
}
// 3. 如果一个类型的参数只出现在一个地方,请重新考虑你是否真的需要它
function greet<Str extends string>(s:Str){
console.log('hello'+s)
}
greet('ssss')
function greet2(s:string){
console.log('hello'+s)
}
greet2('ddd')
可变数量的参数
function f(n:number){
console.log(n.toFixed()) // 0个参数
console.log(n.toFixed(3)) // 1个参数
}
// ?标记这个参数可以有也可以没有
function f(x?:number){
}
f()
f(10)
function f(n:number = 100){
console.log(n.toFixed()) // 0个参数
console.log(n.toFixed(3)) // 1个参数
}
f(123.45)
f() // 不传参,n.toFixed会报错,所以赋一个默认值
当为回调写一个函数类型时,永远不要 写一个 可选参数,除非你打算在不传递该参数的情况下调用函数
function myForEach(arr: any[], callback:(arg:any, index?: number) => void){
for(let i = 0; i<arr.length; i++){
// callback(arr[i], i)
callback(arr[i])
}
}
// myForEach([1,2,3],(a)=> console.log(a))
// myForEach([1,2,3],(a,i)=> console.log(a,i))
// 1 2 3 1 0 2 1 3 2
// i为可选参数
myForEach([1,2,3],(a,i)=> {
// 'i' is possibly 'undefined'.
// console.log(i.toFixed())
})
指定重载签名可以不同方式调用函数
函数签名一般是两个或者多个
function makeDate(timestamp: number): Date;
function makeDate(m:number,d:number,y:number):Date;
function makeDate(mOrTimestamp:number,d?:number,y?:number):Date{
};
// 重载签名
function makeDate(timestamp: number): Date;
function makeDate(m:number,d:number,y:number):Date;
// 实现签名,实现函数的参数必须对重载函数的参数保持一致
function makeDate(mOrTimestamp:number,d?:number,y?:number):Date{
if(d!==undefined && y!==undefined){
return new Date(y,mOrTimestamp,d)
}else{
return new Date(mOrTimestamp)
}
};
const d1 = makeDate(12345678)
const d2 = makeDate(5,6,7)
// No overload expects 2 arguments, but overloads do exist that expect either 1 or 3 arguments. 没有需要 2 参数的重载,但存在需要 1 或 3 参数的重载
// const d3 = makeDate(5,6)
问题
/* function fn12(x:string):void
function fn12(){
}
fn12('1') */
/* function fn12(x:boolean):void
function fn12(x:string):void
// 此重载签名与其实现签名不兼容
// function fn12(x:boolean){
function fn12(x:boolean | string){
} */
function fn12(x:boolean):string
function fn12(x:string):boolean
function fn12(x:boolean | string): string | boolean{
return 'hello'
}
在可能的情况下,总是倾向于使用联合类型的参数而不是重载参数
/* function len(s:string):number
function len(arr:any[]):number
function len(x:any){
return x.length
}
len('hello')
len([1,2,3])
// Argument of type '"hello" | number[]' is not assignable to parameter of type 'any[]'.
len(Math.random() > 0.5 ? 'hello':[1,2,3]) */
function len(x:any[] | string){
return x.length
}
len('hello')
len([1,2,3])
len(Math.random() > 0.5 ? 'hello':[1,2,3])
ts通过代码流分析推断函数中的this应该是什么
const user = {
id: 123,
admin:false,
becomeAdmin: function(){
this.admin = true
}
}
interface DB {
filterUsers(filter:(this:User) => boolean): User[]
}
interface User {
admin:boolean
}
interface DB {
filterUsers(filter: (this:User)=>boolean): User[]
}
const db:DB = {
filterUsers:(filter: (this: User)=> boolean)=>{
let user1:User = {
admin:true
}
let user2:User = {
admin:false
}
return [user1, user2]
}
}
// 这个function不能是箭头函数
const admins = db.filterUsers(function(this:User){
return this.admin
})
// const admins1 = db.filterUsers((this:User)=>{
// return this.admin
// })
console.log(admins) // [ { admin: true }, { admin: false } ]
function f1(a:any){
a.b() // 正确
}
function f2(a:unknown){
a.b()
}
function safeParse(s:string):unknown{
return JSON.parse(s)
}
const obj = safeParse(someRandomString)
function fail(msg:string):never{
throw new Error(msg)
}
function fn(x:string|number){
if(typeof x === 'string'){
}else if(typeof x === 'number'){
}else{
x; // ‘never’ ,这里永远不会被触发
}
}
function doSomething(f:Function){
return f(1,2,3) // 返回值为any,应避免这样做,因为any不安全
}
// 不打算调用就用=> void
function multiply(n: number, ...m: number[]){
return m.map((x)=> n*x)
}
const a = multiply(10, 1,2,3,4) // 10是n,1234被m接收形成数组
// [ 10, 20, 30, 40 ]
const arr1 = [1,2,3]
const arr2 = [4,5,6]
arr1.push(...arr2)
/* const args = [8,5]
const angle = Math.atan2(...args) //扩张参数必须具有元组类型或传递给 rest 参数 */
const args = [8,5] as const
const angle = Math.atan2(...args) //扩张参数必须具有元组类型或传递给 rest 参数
function sum({a,b,c}:{a:number;b:number,c:number}){
console.log(a+b+c)
}
sum({a:10,b:3,c:9}) // 22
一个具有void返回类型的上下文函数类型(type vf = () => void)在实现时,可以返回任何其他的值,但它会被忽略
当一个字面的函数定义一个void的返回类型时,该函数必须不返回任何东西
type voidFunc = () => void
const f1:voidFunc = () => {
return true
}
const f2:voidFunc = () => true
const f3:voidFunc = function(){
return true
}
const v1:void = f1()
const v2 = f2()
const v3 = f3()
function f4():void{
return true
}
const f5 = function(): void{
return true
}
匿名对象 接口命名 类型别名
// 匿名对象
/* function greet(person:{name:string, age:number}){
return 'Hello' + person.name
} */
// 接口命名
/* interface Person {
name:string
age:number
}
function greet(person:Person){
return 'Hello' + person.name
} */
// 类型别名
type Person01 = {
name:string
age:number
}
function greet(person:Person){
return 'Hello' + person.name
}
type Shape = {}
interface PaintOptions{
shape:Shape,
xPos?:number,
yPos?:number
}
/* function paintShape(opts:PaintOptions){
let xPos = opts.xPos
let yPos = opts.yPos
console.log(xPos)
} */
/* function paintShape(opts:PaintOptions){
let xPos = opts.xPos === undefined ? 0:opts.xPos
let yPos = opts.yPos === undefined ? 0:opts.yPos
console.log(xPos)
} */
// 解构
/* function paintShape({shape, xPos = 0, yPos = 0}:PaintOptions){
// let xPos = opts.xPos === undefined ? 0:opts.xPos
// let yPos = opts.yPos === undefined ? 0:opts.yPos
console.log(xPos)
} */
function paintShape({shape:Shape, xPos:number = 0, yPos = 0}:PaintOptions){
console.log(Shape)
console.log(number)
}
const shape:Shape={}
paintShape({shape})
paintShape({shape,xPos:100})
paintShape({shape,yPos:100})
paintShape({shape,xPos:100,yPos:100})
interface SomeType{
readonly prop:string
}
function doSomething(obj:SomeType){
console.log(obj.prop)
// obj.prop = 'hello' // 无法为“prop”赋值,因为它是只读属性
}
interface Home {
readonly resident:{
name:string
age:number
}
}
/* interface Home {
readonly resident:{
name:string
readonly age:number
}
} */
function visitForBirthday(home:Home){
console.log(home.resident.name)
home.resident.age++
}
visitForBirthday({resident:{name:'11',age:11}})
function evict(home:Home){
// home.resident = {// 无法为“resident”赋值,因为它是只读属性
// name:'ss',
// age:15
// }
}
// readonly属性可以通过别名改变
interface Person{
name:string
age:number
}
interface ReadonlyPerson{
readonly name:string
readonly age:number
}
let writablePerson:Person = {
name:'Felix',
age:18
}
let readonlyPerson:ReadonlyPerson = writablePerson
console.log(readonlyPerson.age)//18
writablePerson.age++
console.log(readonlyPerson.age)//19
interface StringArray{
[index: number]:string
}
const myArray:StringArray = ['a','b']
const secondItem = myArray[0]
interface TestString{
[props:string]:number
}
let testString:TestString = {
x:100,
y:100,
// aaa:'aa'
}
interface Animal{
name:string
}
interface Dog extends Animal{
breed:string
}
interface NotOkay{
[index:string]:number | string
length:number
name:string
}
let notOkay:NotOkay = {
x:100,
length:100,
name:'ss'
}
interface ReadonlyStringArray{
readonly [index:number]:string
}
let myArray2:ReadonlyStringArray = ['a','b']
// myArray2[0] = 'aaa' //类型“ReadonlyStringArray”中的索引签名仅允许读取。
interface BasicAddress{
}
interface AddressWithUnit extends BasicAddress {
unit:string
}
interface BasicAddress{
name?:string
street:string
city:string
country:string
postalCode:string
}
/* interface AddressWithUnit{
name?:string
street:string
city:string
country:string
postalCode:string
unit:string
} */
interface AddressWithUnit extends BasicAddress{
unit:string
}
let awu:AddressWithUnit = {
unit:'3单元',
street:'ssss',
city:'xxxx',
country:'qqq',
postalCode:'wree',
name:'v'
}
interface Colorful{
color:string
}
interface Circle{
radius:number
}
interface ColorCircle extends Colorful, Circle{
}
const cc05: ColorCircle = {
color:'red',
radius:100
}
type ColorfulCircle = Colorful & Circle
interface Colorful{
color:string
}
interface Circle{
radius:number
}
type ColorfulCircle = Colorful & Circle
const cc: ColorfulCircle = {
color:'cc',
radius:100
}
function draw(Circle:Colorful & Circle){
console.log(Circle.color)
console.log(Circle.radius)
}
draw({
color:'red',
radius:100
})
如何处理冲突
// 类型合并使用interface
/* interface Sister{
name:string
}
interface Sister{
age:number
}
const sister1:Sister = {
name:'xx',
age:20
} */
// 避免类型冲突用type
type Sister = {
name:string
}
type Sister = { // 标识符“Sister”重复
name:string
}
interface Box{
content:any;
}
interface Box{
content:unknown;
}
interface Box<Type>{
contents:Type
}
let box:Box<string>
/* interface Box{
contents:any
}
let box: Box = {
contents:'hello'
} */
/* interface Box{
contents:unknown
}
let x: Box={
contents:'hello world'
}
if(typeof x.contents === 'string'){
console.log(x.contents.toLowerCase())
}
// console.log(x.contents.toLowerCase()) //“x.contents”的类型为“未知”
console.log((x.contents as string).toLowerCase()) */
/* interface NumberBox{
contents:number
}
interface StringBox{
contents:string
}
interface BooleanBox{
contents:boolean
}
function setContents(box:StringBox,newContents:string):void
function setContents(box:NumberBox,newContents:number):void
function setContents(box:BooleanBox,newContents:boolean):void
function setContents(box:{contents:any},newContents:any){
box.contents = newContents
} */
/* interface Box{
contents:Type
}
interface StringBox{
contents:string
}
let boxA: Box = {
contents:100
}
let boxB:StringBox={
contents:100
}
*/
/* interface Box{
contents:Type
}
interface Apple{
}
let a:Apple={}
type AppleBox = Box
let ab:AppleBox = {
contents:a
}
*/
// 类型别名
type Box<Type> = {
contents:Type
}
type OrNull<Type> = Type | null
type OneOrMany<Type> = Type | Type[]
type OneOrManyOrNull<Type> = OrNull<OneOrMany<Type>>
type OneOrManyOrNullString = OneOrManyOrNull<string>
创建一个在各种类型上工作的组件
function identity(arg:number):number{
return arg
}
// any丢失类型信息
function identity(arg:any):any{
return arg
}
// 需要一种方法来捕获参数类型,以便可以用它来表示返回的内容
// 类型变量,只对类型起作用而不是数值
// 不会丢失任何类型信息
function identity<Type>(arg:Type):Type{
return arg
}
let output = identity<string>("myString")
// 类型参数推断
let output = identity("myString")
function loggingIdentity<Type>(arg:Type):Type{
console.log(arg.length)
return arg
}
// Type是个泛型
// function loggingIdentity(arg:Type):Type{
// console.log(arg.length) // 类型“Type”上不存在属性“length” 解决:规定某个类型
// return arg
// }
function loggingIdentity1<Type>(arg:Array<Type>):Type[]{
console.log(arg.length) // 类型“Type”上不存在属性“length” 解决:规定某个类型
return arg
}
// loggingIdentity('hello') // 5
loggingIdentity1([100,200]) // 2
interface GenericIdentityFn{
<Type>(arg:Type):Type;
}
function identity<Type>(arg:Type):Type{
return arg
}
let myIdentity: <Type>(arg:Type)=> Type = identity
let myIdentity2: <Input>(arg:Input)=> Input = identity
let myIdentity3: {<Type>(arg:Type): Type} = identity
// 泛型接口
interface GenericIdentityFn{
<Type>(arg:Type):Type
}
let myIdentity4: GenericIdentityFn = identity
interface GenericIdentityFn2<Type>{
(arg:Type):Type
}
// let myIdentity5: GenericIdentityFn2 = identity // 泛型类型“GenericIdentityFn2”需要 1 个类型参数。
let myIdentity5: GenericIdentityFn2<string> = identity
类的名称后面加尖括号
class GenericNumber<NumType>{
zeroValue:NumType;
add:(x:NumType, y:NumType) => NumType
}
class GenericNumber<NumType>{
zeroValue:NumType; // tsconfig文件 strictPropertyInitialization为false 就不提示属性“zeroValue”没有初始化表达式,且未在构造函数中明确赋值
add:(x:NumType, y:NumType) => NumType
}
let myGeneric = new GenericNumber<number>()
myGeneric.zeroValue = 0
myGeneric.add = function(x,y){
return x+y
}
let myGeneric2 = new GenericNumber<string>()
myGeneric2.zeroValue = ''
myGeneric2.add = function(x,y){
return x+y
}
// 用一个接口或者type来定义Lengthwise
function loggingIdentity<Type extends Lengthwise>{}
interface Lengthwise {
length:number
}
function loggingIdentity<Type extends Lengthwise>(arg:Type):Type{
console.log(arg.length) // 类型“Type”上不存在属性“length” 解决:规定某个类型
return arg
}
// loggingIdentity(3)//类型“number”的参数不能赋给类型“Lengthwise”的参数。
loggingIdentity('hello')
loggingIdentity([1,2])
<Key extends keyof Type>
function getProperty<Type,Key extends keyof Type>(obj:Type, key:Key){
return obj[key]
}
let x = {
a:1,
b:2,
c:3,
d:4
}
getProperty(x,'a')
// getProperty(x,'m') // 类型“"m"”的参数不能赋给类型“"a" | "b" | "c" | "d"”的参数
// c是类类型,传入c时必须给c定义类型
function create<Type>(c: {new():Type}):Type{
return new c()
}
function create<Type>(c: {new():Type}):Type{
return new c()
}
class BeeKeeper{
hasMask: boolean = true
}
class ZooKeeper{
nametag:string = 'Mikle'
}
class Animal{
numLegs:number = 4
}
class Bee extends Animal{
keeper:BeeKeeper = new BeeKeeper()
}
class Lion extends Animal{
keeper:ZooKeeper = new ZooKeeper()
}
function createInstance<A extends Animal>(c:new()=> A):A{
return new c()
}
createInstance(Lion).keeper.nametag
createInstance(Bee).keeper.hasMask
// createInstance(BeeKeeper) // 类型“typeof BeeKeeper”的参数不能赋给类型“new () => Animal”的参数。 类型 "BeeKeeper" 中缺少属性 "numLegs",但类型 "Animal" 中需要该属性。
接收一个对象类型产生key字符串或者是数字字面量的一个结合或者是一个联合类型
type Point = {x:number;y:number}
// 返回"x"|"y"
type P = keyof Point
const p1:P = 'x'
const p2:P = 'y'
/* type Point = {x:number;y:number}
// 返回"x"|"y"
type P = keyof Point
const p1:P = 'x'
const p2:P = 'y'
const p3:P = 'z' // 不能将类型“"z"”分配给类型“keyof Point” */
type Arrayish = {
[n:number]:unknown
}
type A = keyof Arrayish
const a:A = 0
type Mapish = {
[k:string]:boolean
}
type M = keyof Mapish
const m1:M = 0
const m2:M = '0'
// const m3:M = true // 不能将类型“boolean”分配给类型“string | number”。
引用一个变量或者是属性的类型
typeof 只能修饰一个变量或者是某个对象里面的属性
let s = "hello"
let n:typeof s
n = 'world'
// console.log(typeof 'Hello World')
/* let s = "hello"
// 返回s的类型直接赋给了n
let n:typeof s
n = 'world'
n = 100 // 不能将类型“number”分配给类型“string” */
/* // ReturnType
type Predicate = (x:unknown) => boolean
type K = ReturnType
function f(){
return {
x:10,
y:3
}
}
// type P = ReturnType // “f”表示值,但在此处用作类型。是否指“类型 f”?
type P = ReturnType
const p:P = 100 // 不能将类型“number”分配给类型“{ x: number; y: number; }” */
/* // 不能在typeof后面调用这个函数试图去返回函数的返回结果的类型
// typeof 只能修饰一个变量或者是某个对象里面的属性
function msgbox(){}
// let shouldContinue:typeof msgbox('hello')
let shouldContinue:typeof msgbox
shouldContinue = 100 // 不能将类型“number”分配给类型“() => void” */
去查询另外一个类型上的特定属性
type Person = {
age:number
name:string
alive:boolean
}
type Age = Person["age"]
// Age为number类型
/* type Person = {
age:number
name:string
alive:boolean
}
type Age = Person["age"]
let age: Age = '90' // 不能将类型“string”分配给类型“number” */
interface Person{
name:string
age:number
alive:boolean
}
// type I1=string|number
type I1 = Person['age'|'name']
const i11:I1 = 100
const i12:I1 = ''
// const i13:I1 = true //不能将类型“boolean”分配给类型“I1”
// type I1=string|number|boolean
type I2 = Person[keyof Person]
const i21:I2 = 100
const i22:I2 = ''
const i23:I2 = true
// const i24:I2 = {}
type AliveOrName = 'alive'|'name'
type I3 = Person[AliveOrName]
const I31:I3 = true
const I32:I3 = 'hello'
// const I33:I3 = 100
// type I4 = Person['alive']
const MyArray = [
{name:'Alice',age:15},
{name:'Bob',age:23},
{name:'Eve',age:38},
]
// type Person2 = {name:string,age:number}
type Person2 = typeof MyArray[number]
const p:Person2 = {
name:'xx',
age:12,
// alive:true
}
type Age = typeof MyArray[number]['age']
const age:Age = 11
type Age2 = Person['age']
const age2:Age2 = 300
const key = 'age'
// type Age3 = Person[key] // “key”表示值,但在此处用作类型。是否指“类型 key”?
type Age3 = Person[typeof key]
type key1 = 'age'
type Age31 = Person[key1]
SomeType extends OtherType? TrueType:FalseType
/* interface Animal{
live():void
}
interface Dog extends Animal{
woof():void
}
// type Example1 = number
type Example1 = Dog extends Animal ? number:string
// type Example2 = string
type Example2 = RegExp extends Animal ? number:string */
interface IdLabel{
id:number
}
interface NameLabel{
name:string
}
/* function createLabel(id:number):IdLabel
function createLabel(name:string):NameLabel
function createLabel(nameOrId:string | number):IdLabel | NameLabel
function createLabel(nameOrId:string | number):IdLabel | NameLabel {
throw ''
} */
type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel
function createLabel<T extends number | string>(idOrName:T):NameOrId<T>{
throw ''
}
// type a1 = NameLabel
let a1 = createLabel('typeScript')
// type b1 = IdLabel
let b1 = createLabel(2.5)
// type c1 = NameLabel | IdLabel
let c1 = createLabel(Math.random() > 0.5 ? 'hello':42)
type MessageOf = T extends {message:unknown}? T[‘message’] : never
// type MessageOf = T['message']
// type MessageOf = T['message']
/* type MessageOf = T extends {message:unknown} ? T['message']:never
interface Email{
message:string
}
interface Dog{
bark():void
}
// type EmailMessageContents = string
type EmailMessageContents = MessageOf
const emc: EmailMessageContents = 'balabala...'
type DogMessageContents = MessageOf
// const dmc: DogMessageContents = 'error' // 不能将类型“string”分配给类型“never”。
const dmc: DogMessageContents = 'error' as never */
type Flatten<T> = T extends any[] ? T[number]:T
// type Str = string
type Str = Flatten<string[]>
// type Num = number
type Num = Flatten<number>
提供一种方法推断我们在真实分支中使用infer关键字来进行对比的类型
type Flatten<Type> = Type extends Array<infer Item> ? Item : Type
type GetReturnType<Type> = Type extends (...args:never[]) => infer R
? R
: never
// type Num12 = number
type Num12 = GetReturnType<() => number>
let num: Num = 100
// type Str12 = string
type Str12 = GetReturnType<(x:string) => string>
let str:Str = ''
// type Bools = boolean[]
type Bools = GetReturnType<(a:boolean, b:boolean) => boolean[]>
let bools:Bools = [true,false]
// type Never = never
type Never = GetReturnType<string>
let nev: Never = 'error' as never
function stringOrNum(x:string):number
function stringOrNum(x:number):string
function stringOrNum(x:string | number):string | number
function stringOrNum(x:string | number):string | number{
return Math.random() > 0.5 ? 'hello':23
}
// type T1 = string | number
type T1 = ReturnType <typeof stringOrNum>
const t1:T1 = 100
const t2:T1 = '1'
// const t3:T1 = true
type ToArray<Type> = Type extends any ? Type[]:never
type StrArrOrNumArr = ToArray<string | number>
type ToArray<Type> = Type extends any ? Type[] : never
/* // type StrArrOrNumArr = string[] | number[]
// type StrArrOrNumArr = (string | number)[]
type StrArrOrNumArr = ToArray
// let saon: StrArrOrNumArr = 100 // 不能将类型“number”分配给类型“StrArrOrNumArr”。
let saon: StrArrOrNumArr = [] */
type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never
type StrArrOrNumArr = ToArrayNonDist<string | number>
// let saon: StrArrOrNumArr = [true] // 不能将类型“boolean”分配给类型“string | number”。
let saon: StrArrOrNumArr = [1]