TS系列(5):泛型和类型声明文件

TS系列(1):TS是什么?如何使用?

TS系列(2):类型声明、类型推断和类型总览

TS系列(3):常用类型(详细)

TS系列(4):常用类型之类、抽象类和接口

话接上回,什么是泛型?什么是类型声明文件?

八、泛型

泛型允许我们在定义函数、类或接口时,使用类型参数来表示未指定的类型,这些参数在具体使用时,才被指定具体的类型,泛型能让同一段代码适用于多种类型,同时仍然保持类型的安全性。

举例来说:如下代码中<T>就是泛型,不一定叫T,设置泛型后即可在函数中使用T来表示该类型:

泛型函数

function logData<T>(data: T): T {
    console.log(data)
    return data
}

logData(10) // 不指定泛型,TS可以自动对类型进行推断
logData<number>(100) // 指定泛型
logData<string>('hello') // 指定泛型

泛型数组

// 方式1
function fn1<T>(arr: T[]): T[] {
    console.log(arr.length)
    return arr
}

// 方式2
function fn2<T>(arr: Array<T>): Array<T> {
    console.log(arr.length)
    return arr
}

多个泛型

function logData<T, K>(data1: T, data2: K): T | K {
    console.log(data1, data2)
    return Date.now() % 2 ? data1 : data2
}

logData(100, 'hello') // 不指定泛型,TS会自动对类型进行推断
logData<number, string>(100, 'hello') // 指定泛型
logData<string, boolean>('hello', false) // 指定泛型

泛型接口

// 示例1
interface PersonInterface<T> {
    name: string,
    age: number,
    extraInfo: T
}

let p1: PersonInterface<string>
let p2: PersonInterface<number>

p1 = {
    name: '张三',
    age: 18,
    extraInfo: '厉害人物'
}
p2 = {
    name: '李四',
    age: 18,
    extraInfo: 250
}

// 示例2
interface Info<T> {
    like: T
}
let zhangsan: Info<string> = {
    like: '篮球'
}
let lisi: Info<string[]> = {
    like: ['篮球']
}

// 示例3
interface fn<T> {
    (a1: T, a2: T): T[]
}
let f1: fn<string> = function(a, b) {
    return [a, b]
}
let f2: fn<number> = function(a, b) {
    return [a, b]
}
console.log(f1('1', '2')) // ['1', '2']
console.log(f2(1, 2))			// [1, 2]

泛型约束(指定泛型类型)

// 示例1
interface PersonInterface {
    name: string,
    age: number
}

function logPerson<T extends PersonInterface>(info: T): void {
    console.log(`我叫${info.name},今年${info.age}岁了`)
}

logPerson({ name: '张三', age: 18 })

// 示例2
function fn<T extends string|any[]>(a: T):number {
    return a.length
}
fn('hello') // 正常
fn([1, 2, 3]) // 正常
fn(123) // Argument of type 'number' is not assignable to parameter of type 'string | any[]'

泛型类

class Person<T> {
    constructor(
        public name: string,
        public age: number,
        public extraInfo: T
    ) { }
    speak() {
        console.log(`我叫${this.name},今年${this.age}岁了`)
        console.log(this.extraInfo)
    }
}

const p1 = new Person<string>('小明', 10, '很聪明')

type JobInfo = {
    title: string
    company: string
}

const p2 = new Person<JobInfo>('张三', 30, { title: '总经理', company: '华夏科技公司' })

keyof

interface Info {
    name: string,
    age: number
}
let zhangsan: Info = {
    name: 'zhangsan',
    age: 10
}
getInfoValue(zhangsan, 'name')

// 示例1
function getInfoValue(info: Info, key: string): void {
    // 这里会报错,因为传入的 key 可能不是 Info 的属性
    console.log(info[key])
}

// 示例2
function getInfoValue(info: Info, key: keyof Info): void {
    console.log(info[key])
}

// 示例3
function getInfoValue<T extends keyof Info>(info: Info, key: T): Info[T] {
    return info[key]
}

九、类型声明文件

类型声明文件是 TypeScript 中的一种特殊文件,通常以.d.ts作为扩展名。它的主要作用是为现有的 JavaScript 代码提供类型信息,使得 TypeScript 能够在使用这些 JavaScript 库或模块时进行类型检查和提示

demo.js

export function add(a, b) {
  return a + b
}

export function mul(a, b) {
  return a * b
}

demo.d.ts

declare function add(a: number, b: number): number
declare function mul(a: number, b: number): number

export { add, mul }

example.ts

import { add, mul } from './demo.js'

const x = add(2, 3) // x 类型为 number
const y = mul(4, 5) // y 类型为 number

console.log(x, y)

好了,分享结束,谢谢点赞,下期再见。

在使用 `mapState` 函数中声明 TypeScript 类型时,可以使用以下两种方式: 1. 直接定义类型 可以在 `mapState` 函数中使用对象字面量的方式直接定义类型。例如: ```typescript import { mapState } from 'vuex'; interface RootState { count: number; todos: string[]; } export default { computed: { ...mapState<RootState>({ count: state => state.count, todos: state => state.todos, }), }, }; ``` 在上述示例中,我们通过泛型 `<RootState>` 指定了 `mapState` 函数的类型参数,以便正确地推断出状态的类型。 2. 通过模块化方式定义类型 如果你使用了 Vuex 的模块化功能,可以在模块的类型定义文件声明状态的类型,并在使用 `mapState` 函数时直接引用这些类型。例如: ```typescript // moduleA.ts export interface ModuleAState { foo: string; } // moduleB.ts export interface ModuleBState { bar: number; } // RootState.ts import { ModuleAState } from './moduleA'; import { ModuleBState } from './moduleB'; export interface RootState { moduleA: ModuleAState; moduleB: ModuleBState; } // MyComponent.vue import { mapState } from 'vuex'; import { RootState } from './RootState'; export default { computed: { ...mapState<RootState>({ foo: state => state.moduleA.foo, bar: state => state.moduleB.bar, }), }, }; ``` 在上述示例中,我们将每个模块的状态类型分别定义在对应的模块文件中,并在根状态文件 `RootState.ts` 中引用它们。然后,在组件中使用 `mapState` 函数时,通过泛型 `<RootState>` 引用根状态的类型,并指定每个状态的键名和对应的获取函数。 这两种方式都可以有效地进行 TypeScript 类型声明,你可以根据项目的实际情况选择适合的方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沐爸muba

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值