TypeScript :关键字

简介: 本文介绍了 TypeScript 中的一些核心类型和工具类型,包括 `interface` 和 `type` 的基本使用和区别,以及一些高级类型如 `keyof`、`Record`、`Pick`、`Partial`、`Readonly` 和 `Omit` 的使用方法。文章还详细解释了 `namespace` 的作用和使用场景,帮助开发者更好地组织和管理代码,避免命名冲突,并提高代码的可维护性和可读性。

前言

在 TypeScript 的开发过程中,理解核心类型和工具类型是编写高质量代码的重要基础。本文将深入探讨 TypeScript 中的一些关键概念,首先介绍 interface 和 type 的基本用法与区别,帮助开发者选择合适的声明方式。接下来,我们将讨论一些高级类型,如 keyof、Record、Pick、Partial、Readonly 和 Omit,这些工具类型能够显著提高代码的灵活性与可重用性。

interface

interface(接口) 是 TS 设计出来用于定义对象类型的,可以对对象的形状进行描述。

需要相同里面的属性  

定义 对象 类型   如果使用了这个 类型就需要和这个 接口一样

则更适合用于定义对象的结构,以及类的契约。以下是一个使用interface定义对象结构的示例:

interface 用来 定义 对象结构

type 来 给变量 定义 类型

别名会重合

interface Axxsxs{
    name:String
}
let a:Axxsxs={
    name:"youren",
}

索引签名

interface Axxsxs {
    name: String
    age: number
    [propName: string]: any
}
let a: Axxsxs = {
    name: "youren",
    age: 12,
    a: 1,
    b: 2,
}
// 只需要  前面的  name,age  符合,后面的 就可以不用管

可选操作符    加上  问号 就可有可无

interface Axxsxs {
    name: String
    age?: number
}
let a: Axxsxs = {
    name: "youren",
}

只读   不可以改

interface Axxsxs {
     readonly cd: () => boolean
     readonly :id    //id 一般不可改
   // cd: () => boolean
}
let a: Axxsxs = {
    cd: () => {
        return false;
    }
}
a.cd = () => {
    return true
}

定义函数类型

interface Fn{
    (name: string):number[]
}
const fn:Fn=function(name:string){
    return [1]
}

当缺少interface 里面的属性的时候会报这个错误

<script setup lang="ts">
interface a {
  name: string;
}
interface b extends a{
  submit():void;
}
const youren :b={
  name: 'youren',
  submit() {
    console.log("submit");
  }
}
console.log(youren)
youren.submit()
</script>


type

基本使用

//在 TypeScript 中,type 关键字用于创建自定义类型别名。

其作用就是给类型起一个新名字,可以作用于原始值(基本类型),联合类型,元组以及其它任何你需要手写的类型

主要用于创建联合类型、交叉类型、以及定义复杂的类型别名。下面是一个使用type定义联合类型的示例:

类型别名

<script setup lang="ts">
// ts 里面 string 中s 用小写
//  定义一个ID 标识符 可以是 number or  string
type ID = number | string
// 表示一个人的 对象  包含 name and age
type person = {
  name:string,
  age:number
}
//  表示一个坐标  用 元组表示
type Coordinates = [number, number]
//  表示一个回调函数 ,接受一个参数 并返回 void
type Callback = (result:any)=>void
//  使用 类型别名时  可以直接将别名 作为 类型注解 或 类型 指定
function personID(id:ID){
  //  处理标识符
  console.log(id)
}
// 使用元组
function moveTo(coordinates:Coordinates){
  //  可以传一个 元组
    console.log(coordinates)
}
function fetchData(callback: Callback) {
  // 获取数据并调用回调函数
}
</script>


联合类型

let phone: number | string=123
console.log(phone)
interface People {
    name: string,
    age: number
}
interface Man {
    sex: number
}
const youren = (man: People & Man): void => {
    console.log(man);
}
youren({ name: "youren", age: 10, sex: 1 })
断言  as
const fn =(type:any):boolean=>{
    return type as boolean
}
let b = fn(1)
console.log(b);
any
function warnUser(): void {
    console.log("This is my warning message");
}
never
// 返回never的函数必须存在无法达到的终点
function error(message: string): never {
    throw new Error(message);
}
obj
object 表示非原始类型,也就是除 number , string , boolean , bigint , symbol , null 或 undefined 之外的类型。
as 
let someValue: any = "this is a string";
let strLength: number = (someValue as string).length;
// @errors: 2339
interface Bird {
  fly(): void;
  layEggs(): void;
}
interface Fish {
  swim(): void;
  layEggs(): void;
}
declare function getSmallPet(): Fish | Bird;
let pet = getSmallPet();
pet.layEggs();
// 只有两种可能类型中的一种可用
pet.swim();

联合 类型

使用联合的一种常用技术是使用字面量类型的单个字段,您可以使用该字段来缩小 TypeScript 可能的当前类型。例如,我们将创建一个包含三种类型的联合,这些类型具有一个共享字段。
type NetworkLoadingState = {
  state: "loading";
};
type NetworkFailedState = {
  state: "failed";
  code: number;
};
type NetworkSuccessState = {
  state: "success";
  response: {
    title: string;
    duration: number;
    summary: string;
  };
};
// 创建一个只代表上述类型之一的类型,但你还不确定它是哪个。
type NetworkState =
  | NetworkLoadingState
  | NetworkFailedState
  | NetworkSuccessState;
interface ErrorHandling {
  success: boolean;
  error?: { message: string };
}
interface ArtworksData {
  artworks: { title: string }[];
}
interface ArtistsData {
  artists: { name: string }[];
}
// 这些接口被组合后拥有一致的错误处理,和它们自己的数据
type ArtworksResponse = ArtworksData & ErrorHandling;
type ArtistsResponse = ArtistsData & ErrorHandling;
const handleArtistsResponse = (response: ArtistsResponse) => {
  if (response.error) {
    console.error(response.error.message);
    return;
  }
  console.log(response.artists);
};

interface and type

属性容器和对象容器

  1. 语法:type 使用 type 关键字来定义类型别名,interface 使用 interface 关键字来定义接口。
  2. 功能:type 可以创建任意类型的别名,包括基本类型、联合类型、交叉类型、函数类型等;interface 主要用于定义对象的形状,描述对象的属性和方法。
  3. 可选属性:interface 可以定义可选属性,即属性名后面加上 ? 符号;type 别名不支持可选属性的定义。
  4. 合并声明:interface 支持合并声明,即可以多次声明同一个接口,编译器会将它们合并为一个接口;type 别名不支持合并声明。
  5. 实现类:interface 可以被类实现,类可以通过 implements 关键字来实现接口;type 别名不能被类实现。
  6. 扩展类型:interface 可以通过 extends 关键字来扩展其他接口;type 可以使用交叉类型 & 来扩展其他类型。

总体来说,type 主要用于定义类型别名,可以创建任意类型的别名;interface 主要用于定义对象的形状,描述对象的属性和方法。在实际使用中,可以根据具体需求选择使用 type 还是 interface

接口可以扩展,但type不能使用extends和implement,但是type可以通过交叉类型实现interface的extends行为。interface 可以extends type,同时type也可以与interface类型交叉

interface  定义两个会  重合

type 会报错


implement


  interface Person{
    id:number,
  }
  // implements  一个类继承一个接口
  class Student implements Person{
    //  可以而外的添加,但是原有的必须有
    id:number;
    sex:number
  }
  let xiaoming:Student = {
    id:1,
    sex:1
  }
  console.log(xiaoming)

extends

继承

继承另一个类

所用时需要 用到 继承的属性

先定义一个大类都可以需要的,然后 都可以 继承他

比如id 大家都要就可以选择 继承  ,

interface Person{
        id:number,
    }
    // extends  一个接口 扩展一个接口
    interface Student extends Person{
        sex:number
    }
    let xiaoming:Student = {
        id:1,
        sex:1
    }
    console.log(xiaoming)


typeof

// typeof操作符用于获取变量的类型,因此操作符后面接的始终是一个变量。 // 假如我们在定义类型之前已经有了对象obj,就可以用typeof来定义一个类型。

将一个对象拥有的属性 提取出来   再得到 一个 新的 类型

const  p = {
  name:"c3",
  age:19
}
type Person = typeof p
const p1:Person={
    name:"youren",
    age:10
}
console.log(p1)
//  等同于
// type Person = {
//   name:string,
//   age:number
// }
// 如果对象是一个嵌套的对象,typeof也能够正确获取到它们的类型。
const p1  = {
  name:"c2",
  age:10,
  address:{
    city:"nanchang"
  }
}
type Person = typeof p1
//  等同于
type Person  = {
  name:string,
  age:number,
  address:{
    city:string
  }
}
export const locales = [
  {
    locale: 'se',
    language: 'Swedish'
  },
  {
    locale: 'en',
    language: 'English'
  }
] as const;
//  [number]  为 locale的 字段
type Locale = typeof locales[number]['locale'];
// type Locale = "se" | "en"
typeof locales 获取了 locales 数组的类型。
locales[number] 通过 [number] 索引访问,TypeScript理解为我们想要获取数组中任意一个元素(即任意索引处的元素)的类型。这是因为 number 在这里作为类型查询的一部分,表示我们正在引用一个数组元素的位置,而不是实际的数字值。
['locale'] 然后从该元素的类型中访问 locale 属性的类型。
const people = {
    name: 'liuyz',
    age: 18,
  }
  type INewPeople = typeof people
  // 等同于
  // type INewPeople = {
  //   name: number
  //   age: number
  // }

  const newPeople: INewPeople = {
    name: "zhi",
    age: 18,
  }
  
  type TKeys = keyof typeof newPeople
  // 等同于
  // type TKeys = "name" | "age"

keyof

将 type 里面有的 可以分配给小的

// keyof操作符后面接一个类型,生成由string或者number组成的联合字面量类型。
type Person= {
  name:string,
  age:number
}
type PersonKeys= keyof Person
const key1 :PersonKeys = 'name'
const key2 :PersonKeys = 'age'
// Type '"addr"' is not assignable to type 'keyof Person'.
const key3: PersonKeys = 'addr';
// 我们希望获取一个对象给定属性名的值,为此,
// 我们需要确保我们不会获取 obj 上不存在的属性。所以我们在两个类型之间建立一个约束:
const getProperty = <T,k extends keyof T>(obj:T,key:k)=>{
  return obj[key]
}
const person = {
  name:"c3",
  age:10
}
//  得到了 person 下面的name 属性
console.log(getProperty(person,'name'))
// Argument of type '"addr"' is not assignable to parameter of type '"name" | "age"'.
console.log(getProperty(person, 'addr'));
keyof T返回T的联合字面量类型,extends用来对K进行约束,表示K为联合字面量类型中的一个。
由于我们使用了类型约束,这样我们在调用getProperty的时候,第二个参数key就必须为第一个参数obj中的属性。在尝试传入不存在的addr属性时 TypeScript 就会报错。
type optionsFlags<T>={
  [property in keyof T]:boolean
}
//  use the optionsFlags
type FeatureFlags={
  darkMode:()=>void;
  newUserProfile:()=>void
}
type FeatureOptions = optionsFlags<FeatureFlags>
//  等于
type FeatureOptions={
  darkMode:boolean,
  newUserProfile:boolean
}
在这个例子中,OptionFlags被定义为类型参数为T的一个泛型,[Property in keyof T]表示T所有属性名的迭代,方括号是索引签名语法。所以,OptionFlags包含T类型的所有属性,并将它们的值重新映射为boolean型。

可以基础方法

type OptionsFlag<T>={
[Property in keyof T]:T[Property] extends Function ? T[Property]:boolean
}
type Features={
  darkMode:()=>void
  newUserProfile:()=>void
}
type FeatureOptions = OptionsFlag<Features>
// 相当于
// type  FeatureOptions = {
//   darkMode:()=>void
//   newUserProfile:()=>void
// }
type OptionsFlags<T> = {
  [Property in keyof T]: T[Property] extends Function ? T[Property] : boolean;
};
// use the OptionsFlags
type FeatureFlags = {
  darkMode: () => void;
  newUserProfile: () => void;
};
type FeatureOptions = Record<keyof FeatureFlags,boolean >

record

// 可以看到,Record只是将所有属性映射为T类型之后返回的一个新类型。
// 所以我们可以很容易通过Record实现上面映射类型中的例子。
type Record<k extends keyof any,T>={
  [p in k]:T
}
type TKeys = 'A' | 'B' | 'C'
    // 类型
    interface IPeople {
        name : string,
        age ?: number,
    }
    type TRecord = Record<TKeys, IPeople>
    // ABC 都需要,并且有这些 属性
    let a : TRecord = {
        A: {
            name: "youren",
            age: 10
        },
        B: {
            name: "youren",
            age: 10
        },
        C: {
            name: "youren",
            age: 10
        },
    }
    console.log(a)
  // 等同于
  type TRecord = {
    B: IPeople;
    C: IPeople;
    A: IPeople;
  }
keyof any: 等同于 string | number | symbol ,也就是说 K 只能是这三种类型
P in K: 指循环 K 类型


pick

//它允许从一个对象类型中选择一个或多个属性,并创建一个新类型。
type Pick<T, K  extends keyof T> = {
  [P in K]: T[P];
};
type Coord = Record<'x' | 'y', number>;
type CoordX = Pick<Coord, 'x'>;
// 等用于
type CoordX = {
    x: number;
}
  • keyof T 获取 T 中所有的 key 属性
  • K extends keyof T K 必须继承于 keyof T ,如果 K 中的属性有不属于 keyof T 的则会报错
interface IPeople {
    name:string,
    age?: number,
    sex: string,
  }
  //  大 | 小  
// 小存在于  大
  type TPick = Pick<IPeople, 'name' | 'age'>
  // 等同于
  type TPick = {
    name: string;
    age?: number | undefined;
  }
interface IPeople {
    name:string,
    age?: number,
    sex: string,
    [key: string]: any
  }
// 可以而外加一些其他的
  type TPick = Pick<IPeople, 'name' | 'age' | 'color'>
  等同于
  type TPick = {
    name: string;
    age?: number | undefined;
    color: any;
  }


Partial

局部

将类型定义的所有属性都修改为可选。

type Coord = Partial<Record<'x' | 'y', number>>;
// 等同于
type Coord = {
    x?: number;
    y?: number;
}

```Plain Text

interface IUser {   name: string   age: number   department: string } type optional = Partiallet a:optional={     name:"youren" } console.log(a) // optional的结果如下 // type optional = { //     name?: string | undefined; //     age?: number | undefined; //     department?: string | undefined; // } ```


Readonly


type Coord = Readonly<Record<'x' | 'y', number>>;
// 等同于
type Coord = {
    readonly x: number;
    readonly y: number;
}
// 如果进行了修改,则会报错:
const c: Coord = { x: 1, y: 1 };
c.x = 2; // Error: Cannot assign to 'x' because it is a read-only property.


omit

,它的作用主要是:以一个类型为基础支持剔除某些属性,然后返回一个新类型。

type  Person = {
  name:string,
  age:string,
  location:string,
}
// 接口 | 属性
// 大|小
type  PersonWithoutLocation=Omit<Person, 'location'>
  let a:PersonWithoutLocation={
  name:'youren',
  age:'10',
}
console.log(a)
//  等同于
type Person1={
  name:string,
  age:string
}

namesapce

namespace 用来建立一个容器,内部的所有变量和函数,都必须在这个容器里面使用。

先创建一个test.d.ts 文件

//该文件 : typing.d.ts 
export declare namespace SHOEBOX {
    //export 该类型
   export type Shoe = {
        size:number
        name:string
    }
}

然后在项目中引入使用

<script setup lang="ts">
  import { Shoe } from './typings'

  const shoe : Shoe = {
    size: 1,
    name: "鞋子"
  }
  console.log(shoe)
</script>

主要用来区分的

避免命名冲突:通过将代码分组到不同的命名空间中,可以避免不同模块或库之间的命名冲突。

代码组织:namespace 允许你将相关的代码组织在一起,使得代码结构更加清晰。

模块化:在 TypeScript 中,namespace 可以被看作是一种模块化的方式,尽管在 ES6 中通常使用模块(import/export)来实现这一点。

合并声明:在多个文件中,你可以声明同一个 namespace,TypeScript 编译器会自动将它们合并为一个整体。

访问控制:虽然 TypeScript 中没有严格的访问控制,但 namespace 可以作为一种约定,表明某些内容是内部的,不应该在外部直接访问。

相关文章
|
7月前
|
JavaScript 前端开发
TypeScript 中的 infer 关键字
TypeScript 中的 infer 关键字
104 0
|
7月前
|
存储 JavaScript 前端开发
TypeScript 5.2 beta 浅析:新的关键字 using 与新版装饰器元数据
TypeScript 5.2 beta 浅析:新的关键字 using 与新版装饰器元数据
115 0
|
6月前
|
JavaScript 存储
25.【TypeScript 教程】infer 关键字
25.【TypeScript 教程】infer 关键字
55 2
|
6月前
|
JavaScript
24.【TypeScript 教程】is 关键字
24.【TypeScript 教程】is 关键字
50 0
|
安全
TypeScript-infer关键字和TypeScript-unknown类型
TypeScript-infer关键字和TypeScript-unknown类型
54 0
|
JavaScript 前端开发 Java
TypeScript 基础学习之泛型和 extends 关键字
越来越多的团队开始使用 TS 写工程项目, TS 的优缺点也不在此赘述,相信大家都听的很多了。平时对 TS 说了解,仔细思考了解的也不深,借机重新看了 TS 文档,边学习边分享,提升对 TS 的认知的同时,也希望能在平时的工作中能用上,少写一点 any。
127 0
|
JavaScript
【TypeScript教程】# 11:super关键字
【TypeScript教程】# 11:super关键字
98 0
【TypeScript教程】# 11:super关键字
|
2月前
|
JavaScript 前端开发 安全
深入理解TypeScript:增强JavaScript的类型安全性
【10月更文挑战第8天】深入理解TypeScript:增强JavaScript的类型安全性
63 0
|
2月前
|
JavaScript 前端开发 开发者
深入理解TypeScript:类型系统与实用技巧
【10月更文挑战第8天】深入理解TypeScript:类型系统与实用技巧
|
28天前
|
设计模式 JavaScript 安全
TypeScript性能优化及代码质量提升的重要性、方法与策略,包括合理使用类型注解、减少类型断言、优化模块导入导出、遵循编码规范、加强代码注释等
本文深入探讨了TypeScript性能优化及代码质量提升的重要性、方法与策略,包括合理使用类型注解、减少类型断言、优化模块导入导出、遵循编码规范、加强代码注释等,旨在帮助开发者在保证代码质量的同时,实现高效的性能优化,提升用户体验和项目稳定性。
42 6