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 可以作为一种约定,表明某些内容是内部的,不应该在外部直接访问。

相关文章
|
1天前
|
编解码 Java 程序员
写代码还有专业的编程显示器?
写代码已经十个年头了, 一直都是习惯直接用一台Mac电脑写代码 偶尔接一个显示器, 但是可能因为公司配的显示器不怎么样, 还要接转接头 搞得桌面杂乱无章,分辨率也低,感觉屏幕还是Mac自带的看着舒服
|
3天前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1540 5
|
1月前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
7天前
|
人工智能 Rust Java
10月更文挑战赛火热启动,坚持热爱坚持创作!
开发者社区10月更文挑战,寻找热爱技术内容创作的你,欢迎来创作!
577 22
|
3天前
|
存储 SQL 关系型数据库
彻底搞懂InnoDB的MVCC多版本并发控制
本文详细介绍了InnoDB存储引擎中的两种并发控制方法:MVCC(多版本并发控制)和LBCC(基于锁的并发控制)。MVCC通过记录版本信息和使用快照读取机制,实现了高并发下的读写操作,而LBCC则通过加锁机制控制并发访问。文章深入探讨了MVCC的工作原理,包括插入、删除、修改流程及查询过程中的快照读取机制。通过多个案例演示了不同隔离级别下MVCC的具体表现,并解释了事务ID的分配和管理方式。最后,对比了四种隔离级别的性能特点,帮助读者理解如何根据具体需求选择合适的隔离级别以优化数据库性能。
201 3
|
10天前
|
JSON 自然语言处理 数据管理
阿里云百炼产品月刊【2024年9月】
阿里云百炼产品月刊【2024年9月】,涵盖本月产品和功能发布、活动,应用实践等内容,帮助您快速了解阿里云百炼产品的最新动态。
阿里云百炼产品月刊【2024年9月】
|
10天前
|
Linux 虚拟化 开发者
一键将CentOs的yum源更换为国内阿里yum源
一键将CentOs的yum源更换为国内阿里yum源
571 5
|
23天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
6天前
|
XML 安全 Java
【Maven】依赖管理,Maven仓库,Maven核心功能
【Maven】依赖管理,Maven仓库,Maven核心功能
233 3
|
9天前
|
存储 人工智能 搜索推荐
数据治理,是时候打破刻板印象了
瓴羊智能数据建设与治理产品Datapin全面升级,可演进扩展的数据架构体系为企业数据治理预留发展空间,推出敏捷版用以解决企业数据量不大但需构建数据的场景问题,基于大模型打造的DataAgent更是为企业用好数据资产提供了便利。
327 2