TypeScript 学习手册

TypeScript 学习手册TypeScript 学习手册 JavaScript 是一门动态弱类型语言 对变量的类型非常宽容 而且不会在这些变量和他们的调用者之间建立结构化的契约 TypeScript 是拥有类型系统的 JavaScript 的超集 可以编译成纯 JavaScript 思维方式决定了编程习惯编程习惯奠定了工程质量工程质量划定了能力边界第一章前言强 弱类型语言 动 静态类型语言强类型语言与弱类型语言在强类型语言中 当一个对象从调用函数传递到被调用函数时 其类型必须与被调用函数中声明的类型兼容 通俗定义

TypeScript 学习手册

第一章 前言

强/弱类型语言、动/静态类型语言

  • 强类型语言与弱类型语言
    在强类型语言中,当一个对象从调用函数传递到被调用函数时,其类型必须与被调用函数中声明的类型兼容。
    通俗定义:强类型语言不允许更改变量的数据类型,除非进行强制类型转换。




  • 静态类型语言和动态类型语言
    静态类型语言:在编译阶段确定所有变量的类型,如C++。
    动态类型语言:在执行阶段确定所有变量的类型,如JavaScript。




静态类型语言动态类型语言
对类型极度严格对类型非常管送
立即发现错误Bug可能隐藏数月甚至数年
运行时性能号运行时性能差
自文档化可读性差

动态类型语言的支持者认为:

  • 性能时可以改善的(VB引擎),而语言的灵活性更重要
  • 隐藏的错误可以通过单元测试发现
  • 文档可以通过工具生成

总结

因为JavaScript是动态类型语言,只有在执行阶段才能确定所有变量的类型,这使得我们在编写程序的时候,编辑器无法有效提示错误。

如以下错误,JavaScript就无法提示错误:

// 示例 1 const message = 'Hello World' message.toLowerCase() // 无法得知mesaage是否存在toLowerCase() 方法 message() // 无法得知message() 是否是错误的写法 message.tollowerCase() // TypeScript 提示: Property 'tollowerCase' does not exist on type '"Hello World"'. Did you mean 'toLowerCase'? // 示例 2 const user = { 
    name:"wuyanzu", age:18 } // TypeScript 提示: Property 'location' does not exist on type '{ name: string; age: number; }'. // JavaScript 提示:未定义location user.location 

配置TypeScript环境

安装vscode、node.js、npm,在vscode终端中,安装TypeScript

PS C:\Users\wuyanzu > npm i typescript -g added 1 package in 2s 

执行ts、js文件

tsc helloworld.ts node helloworld.js 

解决ts和js冲突问题(编译后,函数名重复问题):

 tsc --init // 生成tsconfig.json文件,并注释掉"strict": true, 

实现自动编译:

tsc --watch // ts文件发生变化时,js文件自动编译 tsc --noEmitOnError --watch // ts发生错误时,不自动编译 

变量类型声明

//TypeScript 可以推断出变量的类型,因此这时可以不用显示地声明明确变量的类型 let msg = 'hello world' console.log(typeof(msg)) // "string"  msg = 'hello wu' msg = 18 // Type 'number' is not assignable to type 'string'. 

严格模式

// 配置文件 tsconfig.json "strict": true, "noImplicitAny": true, "strictNullChecks": true, 

降级编译

// 配置文件 tsconfig.json "target": "es2016", // 配置JavaScript适配的ea版本 

第二章 数据类型

字符串、数字、布尔

let str: string = 'hello world' let num: number = 100 let bool: boolean = true 

数组

// 数组声明的两种方式 let arr1: number[] = [1, 2, 3] arr1 = ['a'] // Type 'string' is not assignable to type 'number'. let arr2: Array<number> = [4, 5, 6] arr2 = ['a'] // Type 'string' is not assignable to type 'number'. 

any

// any 不进行任何类型检查 let obj1 = { 
    // 系统推断出obj1的类型为"object"  x: 0 } console.log(typeof(obj1)) // "object"  obj1.foo() // Property 'foo' does not exist on type '{ x: number; }'. let obj2: any = { 
    x: 0 } obj2.foo() 

函数

function sayHi (name: string): void{ 
    // string为参数类型注释,void为返回值类型注释 console.log("Hello, " + name) } sayHi("wuyanzu") // "Hello, wuyanzu"  

函数的参数类型声明、可传可不传参数

function allStarsVote(cn: { 
    x: number, y?: number}) { 
    // ?:表示该参数可传可不传 console.log('Uzi 的票数为: ' + cn.x) console.log('XiaoHu 的票数为: ' + cn.y) //console.log('XiaoHu 的票数为: ' + cn.y?.toPrecision(2)) // 在可不传参数调用方法时,可使用?.方式,等同于若为undefined则跳过 } allStarsVote({ 
   x: 123, y: 456}) // "Uzi 的票数为: 123" "XiaoHu 的票数为: 456"  allStarsVote({ 
   x: 123}) // "Uzi 的票数为: 123" "XiaoHu 的票数为: undefined"  

上下文类型

// 上下文类型,TypeScript会根据上下文推断出变量类型 const allStars = ['xiaohu', 'xiaoming', 'uzi'] allStars.forEach((item) => { 
    console.log(item.toLocaleUpperCase()) // TypeScript 可以根据上下文推断出item的类型 }) 

联合类型

// 示例 1 function welcomePeople(x: string[] | string){ 
    if (Array.isArray(x)){ 
    console.log("Hello, " + x.join(' and ')) }else{ 
    console.log("welcome long traveler" + x) } } welcomePeople(['Uzi', 'Xiaohu']) welcomePeople('Uzi') // 示例 2 function sayHi(name: 'wu' | 'zhang' | 'li'){ 
    } sayHi('chen') // Argument of type '"chen"' is not assignable to parameter of type '"wu" | "zhang" | "li"'. sayHi('li') // 示例 3 function compare(a: string, b: string): -1 | 0 | 1 { 
    return a ===b ? 0 : a > b ? 1 : -1 } 

类型别名

type IdType = number | string // 使用type定义一个类型 function sayHi(x: IdType){ 
    console.log(x) } sayHi(6) sayHi('Uzi') 

接口

interface IdType { 
    x: number y: number } function printCoord(pt: IdType){ 
    console.log(pt) } printCoord({ 
    x: 100, y: 200 }) 

类型别名、接口的扩展和添加字段

// 案例1 接口扩展 interface A { 
    name: string } interface B extends A { 
    honey: boolean } const foo1: B = { 
    name: 'winie', honey: true } // 案例2 类型别名扩展 type C = { 
    name: string } type D = C & { 
    honey: boolean } const foo2: D = { 
    name: 'winie', honey: true } // 案例3 向现有的类型添加字段(interface) interface E { 
    name: string } interface E { 
    honey: boolean } const foo3: E = { 
    name: 'winie', honey: true } // 案例4 向现有的类型添加字段(类型别名) 类型别名无法通过重名的类型别名添加字段,只能通过扩展方式添加 type F = { 
    name: string } type F = C & { 
    // Duplicate identifier 'F'. honey: boolean } 

类型断言

与类型注释相同,类型断言由编辑器删除,不会影响代码的运行时行为

const myCanvas1 = document.getElementById('main_canvas') as HTMLCanvasElement //const myCanvas2 = 
   
     document.getElementById('main_canvas') // 报错了 
    const x = 'hello' as number // neither type sufficiently overlaps with the other.  const y = ('hell0' as unknown) as number 

文字类型

let s1 = 'hello world' // s1可以表示任何可能的字符串(重新赋值) const s2 = 'hello world' // s2只能表示成字符串'hello world' 

推断引起的异常

function handleRequest(url: string, method: 'POST' | 'GET' | 'GUESS'){ 
    } const req = { 
    url:"www.google.com", method:'GET' } //handleRequest(req.url, req.method) // Argument of type 'string' is not assignable to parameter of type '"POST" | "GET" | "GUESS"'. // 原因:req.method被推断为string方法,不满足 type '"POST" | "GET" | "GUESS" // 解决方式1: handleRequest(req.url, req.method as 'GET') // 解决方式2: const req2 = { 
    url:"www.google.com", method:'GET' as 'GET' } handleRequest(req2.url, req2.method) // 解决方式3: const req3 = { 
    url:"www.google.com", method:'GET' as 'GET' } as const handleRequest(req3.url, req3.method) 

null 和 undefined 类型

null 表示不存在

undefined 表示未初始化的值

枚举

enum Color { 
   Red, Green, Blue} let c: Color = Color.Green; console.log(c) // 1 console.log(Color) { 
    "0": "Red", "1": "Green", "2": "Blue", "Red": 0, "Green": 1, "Blue": 2 } 

bigint、symbol

Symbols是不可改变且唯一的

let sym2 = Symbol("key"); let sym3 = Symbol("key"); sym2 === sym3; // false, symbols是唯一的 

第三章 条件判断

=== ===== 

类型谓词

类型谓词是一种特殊的返回类型,它向Typescript编译器发出一个特定值是什么类型的信号。类型谓词总是附加到接受单个参数并返回布尔值的函数。类型谓词表示为 argumentName is Type

function isFish(pet: Fish | Bird): pet is Fish { 
    return (pet as Fish).swim !== undefined; } 

这里的 pet is Fish 就是类型谓词,pet 必须是函数的参数。当 isFinis() 调用并且返回 true 的时候,ts就会把该变量的类型范围缩小为某一具体类型。

type Fish = { 
    name: string, swim: () => void } type Brid = { 
    name:string, fly: () => void } const isFish = (pet: Fish | Brid): pet is Fish => { 
    return (pet as Fish).swim !== undefined } const getSmallPet = (): Fish | Brid => { 
    let brid: Brid = { 
    name: "sbrid", fly(){ 
    } } let fish: Fish = { 
    name:"sfish", swim(){ 
    } } return true ? brid : fish; } let pet = getSmallPet(); if (isFish(pet)){ 
    pet.swim(); } else { 
    pet.fly(); } const zoo: (Fish | Brid)[] = [getSmallPet(),getSmallPet()]; const underWater: Fish[] = zoo.filter(isFish); const underWater2: Fish[] = zoo.filter(isFish) as Fish[]; 

xxx

11 

第三章 函数

type GreetFunction = (arg: string) => void // 定义一个函数类型 function greeter(fn:GreetFunction, arg1: string){ 
    fn(arg1) } function printToConsole(arg: string){ 
    console.log(arg) // "hello world"  } greeter(printToConsole,"hello world") // greeter(printToConsole("a"),"hello world") 的写法是错误的,第一个参数只能是GreetFunction函数类型 

泛型

function firstElement<Type>(arr: Type[]): Type | undefined{ 
    return arr[0] } firstElement(['a', 'b', 'c']) firstElement<number>([1, 2, 3]) 

泛型限制条件 extends

// 下文的extends并非真正的继承,而是简单的限制条件 function longest<Type extends { 
    length: number }>(a: Type, b: Type){ 
    if (a.length >= b.length){ 
    return a }else{ 
    return b } } longest([1, 2], [2, 3, 4]) longest("wuyanzu", "liangchaowei") longest(10, 100) // Argument of type 'number' is not assignable to parameter of type '{ length: number; }'. 

编写优秀通用函数的准则

  • 可能的情况下,使用类型参数本身,而不是对其进行约束
  • 总是尽可能少地使用类型参数
  • 如果一个类型的参数只出现在一个地方,请重新考虑你是否真的需要它

函数参数

当为回调写一个函数类型时,永远不要写一个可选参数,除非你打算在不传递该参数的情况下调用函数。

函数重载签名、实现签名

// 原始类型 let bool: boolean = true let num: number | undefined | null = 123 let str: string = 'abc' // str = 123 Type '123' is not assignable to type 'string'. // 数组 let arr1: number[] = [1, 2, 3] let arr2: Array<number | string> = [1, 2, 3, '4'] // 元组 let tuple: [number, string] = [0, '1'] // tuple.push(2) 强烈不推荐 // console.log(tuple) // tuple[2] // 函数 let add = (x: number, y: number) => x + y let compute: (x: number, y: number) => number compute = (a, b) => a + b // 对象 let obj: { 
    x: number, y: number } = { 
    x: 1, y: 2 } obj.x = 3 // symbol let s1: symbol = Symbol() let s2 = Symbol() // console.log(s1 === s2) // undefined, null let un: undefined = undefined let nu: null = null num = undefined num = null // void let noReturn = () => { 
   } // any let x x = 1 x = [] x = () => { 
   } // never let error = () => { 
    throw new Error('error') } let endless = () => { 
    while(true) { 
   } } 
// 数字枚举 enum Role { 
    Reporter = 1, Developer, Maintainer, Owner, Guest } // console.log(Role.Reporter) // console.log(Role) // 字符串枚举 enum Message { 
    Success = '恭喜你,成功了', Fail = '抱歉,失败了' } // 异构枚举 容易混乱,不推荐使用 enum Answer { 
    N, Y = 'Yes' } // 枚举成员 // Role.Reporter = 0 enum Char { 
    // const member a, b = Char.a, c = 1 + 3, // computed member d = Math.random(), e = '123'.length, f = 4 } // 常量枚举 会被编译阶段移除 const enum Month { 
    Jan, Feb, Mar, Apr = Month.Mar + 1, // May = () => 5 } let month = [Month.Jan, Month.Feb, Month.Mar] // 枚举类型 enum E { 
    a, b } enum F { 
    a = 0, b = 1 } enum G { 
    a = 'apple', b = 'banana' } let e: E = 3 let f: F = 3 // console.log(e === f) let e1: E.a = 3 let e2: E.b = 3 let e3: E.a = 3 // console.log(e1 === e2) 无法比较,类型不同 // console.log(e1 === e3) 可以比较,类型相同 let g1: G = G.a let g2: G.a = G.a 

总结:将程序中不容易记忆的硬编码,或者是未来可能改变的常量抽取出来,定义成枚举类型,提高程序的可读性和可维护性。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/207371.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午1:58
下一篇 2026年3月19日 下午1:59


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号