首页 > 其他分享 >#Ts篇: ts学习再梳理

#Ts篇: ts学习再梳理

时间:2024-11-17 22:45:49浏览次数:3  
标签:string ts number Ts let 类型 报错 type 梳理

ts类型梳理

类型声明的写法,一律为在标识符后面添加“冒号 + 类型”。函数参数和返回值,也是这样来声明类型。

function toString(num: number): string {
  return String(num);
}

上面示例中,函数toString()的参数num的类型是number。参数列表的圆括号后面,声明了返回值的类型是string。

值代码和类型代码

TypeScript 代码只涉及类型,不涉及值。所有跟“值”相关的处理,都由 JavaScript 完成。

运行环境网址

https://www.typescriptlang.org/play/?#code/PTAEHUFMBsGMHsC2lQBd5oBYoCoE8AHSAZVgCcBLA1UABWgEM8BzM+AVwDsATAGiwoBnUENANQAd0gAjQRVSQAUCEmYKsTKGYUAbpGF4OY0BoadYKdJMoL+gzAzIoz3UNEiPOofEVKVqAHSKymAAmkYI7NCuqGqcANag8ABmIjQUXrFOKBJMggBcISGgoAC0oACCbvCwDKgU8JkY7p7ehCTkVDQS2E6gnPCxGcwmZqDSTgzxxWWVoASMFmgYkAAeRJTInN3ymj4d-jSCeNsMq-wuoPaOltigAKoASgAywhK7SbGQZIIz5VWCFzSeCrZagNYbChbHaxUDcCjJZLfSDbExIAgUdxkUBIursJzCFJtXydajBBCcQQ0MwAUVWDEQC0gADVHBQGNJ3KAALygABEAAkYNAMOB4GRonzFBTBPB3AERcwABS0+mM9ysygc9wASmCKhwzQ8ZC8iHFzmB7BoXzcZmY7AYzEg-Fg0HUiQ58D0Ii8fLpDKZgj5SWxfPADlQAHJhAA5SASPlBFQAeS+ZHegmdWkgR1QjgUrmkeFATjNOmGWH0KAQiGhwkuNok4uiIgMHGxCyYrA4PCCJSAA

any

1.使用场景,某些需要关闭验证
2.为了适配老的js项目
只要开发者使用了any类型,就表示开发者想要自己来处理这些代码,所以就不对any类型进行任何限制,怎么使用都可以。

从集合论的角度看,any类型可以看成是所有其他类型的全集,包含了一切可能的类型。
TypeScript 将这种类型称为“顶层类型”(top type),意为涵盖了所有下层。

缺点
any类型除了关闭类型检查,还有一个很大的问题,就是它会“污染”其他变量。

let x: any = "hello";
let y: number;

y = x; // 不报错

y * 123; // 不报错
y.toFixed(); // 不报错

unknown

为了解决any类型“污染”其他变量的问题
它与any含义相同,表示类型不确定,可能是任意类型,但是它的使用有一些限制,不像any那样自由,可以视为严格版的any。

首先,unknown类型的变量,不能直接赋值给其他类型的变量(除了any类型和unknown类型)。

let v: unknown = 123;

let v1: boolean = v; // 报错
let v2: number = v; // 报错

其次,不能直接调用unknown类型变量的方法和属性。

let v1: unknown = { foo: 123 };
v1.foo; // 报错

let v2: unknown = "hello";
v2.trim(); // 报错

let v3: unknown = (n = 0) => n + 1;
v3(); // 报错

再次,unknown类型变量能够进行的运算是有限的,只能进行比较运算(运算符==、=、!=、!、||、&&、?)、取反运算(运算符!)、typeof运算符和instanceof运算符这几种,其他运算都会报错。

答案是只有经过“类型缩小”,unknown类型变量才可以使用。所谓“类型缩小”,就是缩小unknown变量的类型范围,确保不会出错

never

ypeScript 还引入了“空类型”的概念,即该类型为空,不包含任何值。
由于不存在任何属于“空类型”的值,所以该类型被称为never,即不可能有这样的值。
使用场景
1 主要是在一些类型运算之中,保证类型运算的完整性
2 不可能返回值的函数,返回值的类型就可以写成never
3 如果一个变量可能有多种类型(即联合类型),通常需要使用分支处理每一种类型。这时,处理所有可能的类型之后,剩余的情况就属于never类型。

function fn(x: string | number) {
  if (typeof x === "string") {
    // ...
  } else if (typeof x === "number") {
    // ...
  } else {
    x; // never 类型
  }
}

never类型的一个重要特点是,可以赋值给任意其他类型。

为什么never类型可以赋值给任意其他类型呢?这也跟集合论有关,空集是任何集合的子集。TypeScript 就相应规定,任何类型都包含了never类型。因此,never类型是任何其他类型所共有的,TypeScript 把这种情况称为“底层类型”(bottom type)。

总之,TypeScript 有两个“顶层类型”(any和unknown),但是“底层类型”只有never唯一一个。

包装对象类型与字面量类型

"hello"; // 字面量
new String("hello"); // 包装对象

了区分这两种情况,TypeScript 对五种原始类型分别提供了大写和小写两种类型。
Boolean 和 boolean
String 和 string
Number 和 number
BigInt 和 bigint
Symbol 和 symbol

const s1: String = "hello"; // 正确
const s2: String = new String("hello"); // 正确

const s3: string = "hello"; // 正确
const s4: string = new String("hello"); // 报错

建议只使用小写类型,不使用大写类型。因为绝大部分使用原始类型的场合,都是使用字面量,不使用包装对象

Object 类型与 object 类型

大写的Object类型代表 JavaScript 语言里面的广义对象。所有可以转成对象的值,都是Object类型,这囊括了几乎所有的值。

let obj: Object;

obj = true;
obj = "hi";
obj = 1;
obj = { foo: 123 };
obj = [1, 2];
obj = (a: number) => a + 1;

上面示例中,原始类型值、对象、数组、函数都是合法的Object类型。

小写的object类型代表 JavaScript 里面的狭义对象,即可以用字面量表示的对象,只包含对象、数组和函数,不包括原始类型的值。

let obj: object;

obj = { foo: 123 };
obj = [1, 2];
obj = (a: number) => a + 1;
obj = true; // 报错
obj = "hi"; // 报错
obj = 1; // 报错

值类型

let x: 5 = 5;
let y: number = 4 + 1;

x = y; // 报错
y = x; // 正确

联合类型 |

联合类型A|B表示,任何一个类型只要属于A或B,就属于联合类型A|B

let x: string | number;
x = 123; // 正确
x = "abc"; // 正确

交叉类型

指的多个类型组成的一个新类型,使用符号&表示。

let obj: { foo: string } & { bar: string };

obj = {
  foo: "hello",
  bar: "world",
};

上面示例中,变量obj同时具有属性foo和属性bar

type类型

type命令用来定义一个类型的别名。

type Age = number;

let age: Age = 55;

上面示例中,type命令为number类型定义了一个别名Age。这样就能像使用number一样,使用Age作为类型

typeof

console.log(typeof undefined); // "undefined"
console.log(typeof 0);         // "number"
console.log(typeof 123);       // "number"
console.log(typeof -1.5);      // "number"
console.log(typeof NaN);       // "number" (注意:尽管 NaN 表示“不是数字”,但其类型仍然是 number)
console.log(typeof true);      // "boolean"
console.log(typeof false);     // "boolean"
console.log(typeof "");        // "string"
console.log(typeof "hello");   // "string"
console.log(typeof [1, 2, 3]); // "object" (数组被视为对象)
console.log(typeof {a: 1});    // "object"
console.log(typeof null);      // "object" (这是一个历史遗留问题,null 实际上表示空值)
console.log(typeof function(){}); // "function"
console.log(typeof class {});  // "function" (类也是函数的一种形式)

另外,typeof命令的参数不能是类型

块级类型声明

if (true) {
  type T = number;
  let v: T = 5;
} else {
  type T = string;
  let v: T = "hello";
}

上面示例中,存在两个代码块,其中分别有一个类型T的声明。这两个声明都只在自己的代码块内部有效,在代码块外部无效。

类型的兼容

type T = number | string;

let a: number = 1;
let b: T = a;

上面示例中,变量a和b的类型是不一样的,但是变量a赋值给变量b并不会报错。这时,我们就认为,b的类型兼容a的类型。

数组的类型

1 数组的类型有两种写法。

let arr: number[] = [1, 2, 3];

如果数组成员的类型比较复杂,可以写在圆括号里面

let arr: (number | string)[];

2 数组类型的第二种写法是使用 TypeScript 内置的 Array 接口。

let arr: Array<number> = [1, 2, 3];
只读数组,const 断言

TypeScript 允许声明只读数组,方法是在数组类型前面加上readonly关键字。

const arr: readonly number[] = [0, 1];

arr[1] = 2; // 报错
arr.push(3); // 报错
delete arr[0]; // 报错

Index signature in type ‘readonly number[]’ only permits reading.
Property ‘push’ does not exist on type ‘readonly number[]’.
Index signature in type ‘readonly number[]’ only permits reading.

元组

元组(tuple)是 TypeScript 特有的数据类型,

JavaScript 没有单独区分这种类型。

它表示成员类型可以自由设置的数组,即数组的各个成员的类型可以不同。

元组必须明确声明每个成员的类型。

const s: [string, string, boolean] = ["a", "b", true];

元组类型的写法,与上一章的数组有一个重大差异

数组的成员类型写在方括号外面(number[]),

元组的成员类型是写在方括号里面([number])。

TypeScript 的区分方法是,成员类型写在方括号里面的就是元组,写在外面的就是数组

let a: [number] = [1];

上面示例中,变量a是一个元组,只有一个成员,类型是number。


元组成员的类型可以添加问号后缀(?),表示该成员是可选的

let a: [number, number?] = [1];

symbol类型

函数的类型

function hello(txt: string): void {
  console.log("hello " + txt);
}

,函数hello()在声明时,需要给出参数txt的类型(string),以及返回值的类型(void),后者写在参数列表的圆括号后面。void类型表示没有返回值。


函数返回 void 类型

代表函数没有返回值

function f(): void {
  return 123; // 报错
}

如果返回其他值,就会报错。

函数返回 never类型

// 正确
function sing(): void {
  console.log("sing");
}

// 报错
function sing(): never {
  console.log("sing");
}

上面示例中,函数sing()虽然没有return语句,但实际上是省略了return undefined这行语句,真实的返回值是undefined。所以,它的返回值类型要写成void,而不是never,写成never会报错。

高阶函数

一个函数的返回值还是一个函数,那么前一个函数就称为高阶函数(higher-order function)

(someValue: number) => (multiplier: number) => someValue * multiplier;

函数重载

有些函数可以接受不同类型或不同个数的参数,并且根据参数的不同,会有不同的函数行为。这种根据参数类型不同,执行不同逻辑的行为,称为函数重载(function overload)。

reverse("abc"); // 'cba'
reverse([1, 2, 3]); // [3, 2, 1]

对象

一旦声明了类型,对象赋值时,就不能缺少指定的属性,也不能有多余的属性。

type MyObj = {
  x: number;
  y: number;
};

const o1: MyObj = { x: 1 }; // 报错
const o2: MyObj = { x: 1, y: 1, z: 1 }; // 报错

上面示例中,变量o1缺少了属性y,变量o2多出了属性z,都会报错。

接口赋值类型
const {
  id,
  name,
  price,
}: {
  id: string;
  name: string;
  price: number;
} = product;
interface

interface 是对象的模板,可以看作是一种类型约定,中文译为“接口”。

使用了某个模板的对象,就拥有了指定的类型结构。

interface 继承 interface
interface Shape {
  name: string;
}

interface Circle extends Shape {
  radius: number;
}
interface 继承 type
type Country = {
  name: string;
  capital: string;
};

interface CountryWithPop extends Country {
  population: number;
}
接口合并
interface Box {
  height: number;
  width: number;
}

interface Box {
  length: number;
}

两个Box接口会合并成一个接口,同时有height、width和length三个属性。

interface 与 type 的异同

interface命令与type命令作用类似,都可以表示对象类型。

很多对象类型即可以用 interface 表示,也可以用 type 表示。而且,两者往往可以换用,几乎所有的 interface 命令都可以改写为 type 命令。

  1. 它们的相似之处,首先表现在都能为对象类型起名。 —创造一个值,编译后依然存在。如果只是单纯想要一个类型,应该使用type或interface

interface 与 type 的区别有下面几点。

(1)type能够表示非对象类型,而interface只能表示对象类型(包括数组、函数等)。

(2)interface可以继承其他类型,type不支持继承。


继承的主要作用是添加属性,type定义的对象类型如果想要添加属性,只能使用&运算符,重新定义一个类型。

type Animal = {
  name: string;
};

type Bear = Animal & {
  honey: boolean;
};

上面示例中,类型Bear在Animal的基础上添加了一个属性honey。

非空断言!

let value: string | null = "Hello";

// 使用非空断言
let length = value!.length;

console.log(length); // 输出:5

在这个例子中,value 的类型是 string | null,但在使用 value!.length 时,我们通过 ! 告诉编译器 value 不会是 null,因此可以直接访问其属性 length。

类的 interface 接口

implements 关键字
interface Country {
  name: string;
  capital: string;
}
// 或者
type Country = {
  name: string;
  capital: string;
};

class MyCountry implements Country {
  name = "";
  capital = "";
}

interface或type都可以定义一个对象类型。

类MyCountry使用implements关键字,表示该类的实例对象满足这个外部类型。

可访问性修饰符

类的内部成员的外部可访问性,由三个可访问性修饰符(access modifiers)控制:

public、

private和protected。

public修饰符表示这是公开成员,外部可以自由访问

private修饰符表示私有成员,只能用在当前类的内部,类的实例和子类都不能使用该成员

protected修饰符表示该成员是保护成员,只能在类的内部使用该成员,实例无法使用该成员,但是子类内部可以使用。

静态成员

类的内部可以使用static关键字,定义静态成员。

静态成员是只能通过类本身使用的成员,不能通过实例对象使

泛型类
this 问题

泛型

函数返回值的类型与参数类型是相关的

function getFirst(arr) {
  return arr[0];
}

上面示例中,函数getFirst()总是返回参数数组的第一个成员。参数数组是什么类型,返回值就是什么类型。

函数的类型声明只能写成下面这样。

function f(arr: any[]): any {
  return arr[0];
}

为了解决这个问题,TypeScript 就引入了“泛型”(generics)。泛型的特点就是带有“类型参数”(type parameter)。

function getFirst<T>(arr: T[]): T {
  return arr[0];
}

上面示例中,函数getFirst()的函数名后面尖括号的部分,就是类型参数,参数要放在一对尖括号(<>)里面。本例只有一个类型参数T,可以将其理解为类型声明需要的变量,需要在调用时传入具体的参数类型。


接口的泛型写法

interface Box<Type> {
  contents: Type;
}

let box: Box<string>;

Enum类型

as 类型断言

TypeScript 提供了“类型断言”这样一种手段,允许开发者在代码中“断言”某个值的类型,告诉编译器此处的值是什么类型。TypeScript 一旦发现存在类型断言,就不再对该值进行类型推断,而是直接采用断言给出的类型。

type T = "a" | "b" | "c";

let foo = "a";
let bar: T = foo as T; // 正确

上面示例中,最后一行的foo as T表示告诉编译器,变量foo的类型断言为T,所以这一行不再需要类型推断了,编译器直接把foo的类型当作T,就不会报错了。

类型断言有两种语法。

// 语法一:<类型>值
value;

// 语法二:值 as 类型
value as Type;

标签:string,ts,number,Ts,let,类型,报错,type,梳理
From: https://blog.csdn.net/weixin_47075554/article/details/143764092

相关文章

  • 鸿蒙Next模糊接口梳理
    foregroundBlurStyle和backgroundBlurStyleforegroundBlurStyle(value:BlurStyle,options?:ForegroundBlurStyleOptions)backgroundBlurStyle(value:BlurStyle,options?:BackgroundBlurStyleOptions)第一个参数都是模糊材质,用的是鸿蒙系统定制好的一套模糊参数,封装了模糊......
  • 010 Including Bootstrap 4
    CDNGetstartedwithBootstrap·Bootstrapv5.3Template<!doctypehtml><htmllang="en"><head><metacharset="utf-8"><metaname="viewport"content="width=device-width,initial-scal......
  • HDLBIts习题(7):状态机
    (1)较难习题1:134题(fsm_ps2data)    有个积攒数据的过程。(1)较难习题2:135题(fsm_serial)        读清题意,有一个检验选择是否发送的进程。(3)较难习题3:137题(fsm_serialdp)    加入了奇偶校验位检测机制(4)较难习题4:138题(fsm_hdlc)   ......
  • HDLBIts习题(2):位操作,For循环(generate与integer)
    (1)冷门习题1:VerilogLanguage-MoreVerilogFeatures-Reductionoperators    一个矢量的位操作,多比特矢量操作会变得方便。(2)冷门习题2:VerilogLanguage-MoreVerilogFeatures-Combinationfor-loop:Vectorreversal2     Verilog中的for循环(3......
  • 基于大语言模型的自治代理综述 《A Survey on Large Language Model based Autonomous
    图2基于LLM的自治代理架构设计的统一框架基于大语言模型的自治代理综述《ASurveyonLargeLanguageModelbasedAutonomousAgents》自治代理长期以来一直是学术界和工业界的研究热点。以前的研究往往侧重于在孤立的环境中训练知识有限的代理,这与人类的学习过程存......
  • 前端 易混淆知识点梳理
    目录一、严格模式与非严格模式二、双等于三等的区别三、防抖和节流四、原型和原型链五、页面重绘和回流六、script标签async和defer七、普通函数和箭头函数的区别八、JS闭包1、闭包特点2、闭包作用3、闭包风险4、运用场景1)常见闭包2)实现模块化3)缓存函数4)封装私......
  • 轻松获取免费SSL证书,为您的网站安全保驾护航——推荐freegetssl.com
    在这个信息时代,网络安全至关重要。为了保护您的网站数据安全和用户隐私,为您的网站安装SSL证书刻不容缓。今天,为您推荐一款便捷、高效的免费SSL证书获取平台——freegetssl.com。【一键申请,轻松获取】freegetssl.com为您提供一站式SSL证书申请服务,只需简单几步操作,即可轻松获取DV......
  • 天玄链HotStuff共识算法
    共识协议最早被使用在分布式容错系统当中,保证系统整体对外表现状态的一致性和活性。而区块链可以理解为一种拜占庭容错的分布式系统,区块链节点通过共识协议对输入的状态读写指令顺序达成一致,保证分布式系统执行指令顺序一致性,实现最终状态的一致性。其中,较为经典的共识算法簇 ......
  • Uncertainty of Thoughts: Uncertainty-Aware Planning Enhances Information Seeking
    目录概UoT代码HuZ.,LiuC.,FengX.,ZhaoY.,NgS.,LuuA.T.,HeJ.,KohP.W.andHooiB.Uncertaintyofthoughts:Uncertainty-awareplanningenhancesinformationseekinginlargelanguagemodels.NeurIPS,2024.概通过判断问题所导致的不确定性降低程度来......
  • ECharts饼图-饼图33,附视频讲解与代码下载
    引言: 在数据可视化的世界里,ECharts凭借其丰富的图表类型和强大的配置能力,成为了众多开发者的首选。今天,我将带大家一起实现一个饼图图表,通过该图表我们可以直观地展示和分析数据。此外,我还将提供详细的视频讲解和代码下载链接,帮助大家快速上手。一、图表效果预览二、视频......