文章目录
interface 和 type 的区别
1.定义和用途:
interface
:interface被用作定义对象的类型,它描述了一个对象应有的形状(即属性和方法)。
interface Person {
firstName: string;
lastName: string;
age?: number; // 可选属性
fullName(): string; // 方法
}
type
:除了对象类型,type还可以定义联合类型、交叉类型、元组等,并支持更高级的类型操作。
type Name = string;
// 函数声明
type NameResolver = () => string;
type NameOrResolver = Name | NameResolver;
// 元组
type Tuple = [string, number];
const myTuple: Tuple = ['hello', 123];
// 映射类型
type Keys = 'a' | 'b' | 'c';
type Obj = { [K in Keys]: string }; // { a: string; b: string; c: string; }
2.可扩展性:
interface
是可以扩展的,你可以使用extends
关键字来扩展一个interface
。
interface Animal {
name: string;
}
interface Mammal extends Animal {
milk: boolean;
}
type
通过交叉类型 (&) 来实现类似的功能。
type Animal = {
name: string;
};
type Mammal = Animal & { milk: boolean };
3.声明合并:
interface
可以声明合并,即如果多个interface
定义了相同的名称,它们会被合并成一个。
interface User {
id: number;
}
interface User {
name: string;
}
const user: User = {
id: 1,
name: 'John'
};
type
不支持声明合并。
TypeScript 泛型
TypeScript 中的泛型(Generics)是一种在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。泛型的主要目的是在定义组件时,创建可重用的代码,这些代码可以支持多种数据类型,从而提高了代码的复用性和灵活性。
泛型函数
泛型函数是在定义时不指定参数类型,而在调用时传入类型参数。类型参数用尖括号 <> 包围,并放在函数名后面。
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString"); // 输出: "myString"
let numOutput = identity<number>(123); // 输出: 123
在这个例子中,T
是一个类型变量,表示任意类型。当我们调用 identity
函数时,可以传入任意类型的参数,并在返回值时保持相同的类型。
泛型类
泛型类是在类定义中引入类型参数。
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
console.log(myGenericNumber.add(10, 20)); // 输出: 30
在这个例子中,GenericNumber
类有一个类型参数 T
,可以用来定义 zeroValue
属性和 add
方法的类型。
泛型接口
泛型接口允许我们定义接口时,不预先指定具体的类型,而是在实现接口的时候指定。
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
在这个例子中,GenericIdentityFn 是一个泛型接口,它描述了一个接受类型 T 的参数并返回相同类型 T 结果的函数类型。然后我们使用这个函数类型去描述 identity 函数。
泛型约束
有时候我们可能希望泛型类型 T 必须满足一定的条件。这时候,我们可以使用接口来定义约束。
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 因为 T 是 Lengthwise 的子类,所以可以访问 length 属性
return arg;
}
loggingIdentity({length: 10, value: 3}); // 输出: 10
在这个例子中,我们定义了一个 Lengthwise
接口,它有一个 length
属性。然后,我们定义了一个泛型函数 loggingIdentity
,它的类型参数 T
必须满足 Lengthwise
接口的约束。
TypeScript中 Any 和 UNKnown
any
类型在 TypeScript 中表示可以是任意类型的值。当你不知道一个变量的确切类型,或者你想跳过类型检查时,你可以使用 any 类型。使用 any 类型可以绕过 TypeScript 的类型系统,但这通常不是一种好的做法,因为它会失去类型安全的优势。
let variable: any;
variable = "Hello";
variable = 123;
variable = true;
unknown
类型是 TypeScript 3.0 中引入的一个新类型,它表示一个值可以是任意类型,但你不能直接对该值进行任何操作,除了赋值给另一个 unknown
类型的变量、赋值给 any
类型的变量、或者进行类型断言或类型守卫。这有助于在编译时捕获可能的类型错误。
let value: unknown;
value = "Hello";
// value.toUpperCase(); // 错误!不能直接调用方法,因为 value 的类型是 unknown
if (typeof value === "string") {
console.log(value.toUpperCase()); // 正确!在类型守卫之后,我们知道 value 是字符串
}
总结
any
类型用于当你不知道或不想指定一个变量的类型时。它绕过了类型检查,通常不推荐使用,因为它会失去 TypeScript 的类型安全优势。unknown
类型用于当你希望保留对变量值的类型不确定性,同时仍然能够在编译时捕获可能的类型错误时。它强制你进行显式的类型检查或类型断言,以确保对变量的操作是类型安全的。
在编写 TypeScript 代码时,通常建议使用 unknown
类型而不是 any
类型,以保留类型安全性。当你确实需要绕过类型检查时,可以使用 any
类型,但要谨慎使用,并尽量避免在大型代码库中使用它。
使用ts写一个对象属性约束
使用{useName:string, password:number}
约束传入的userData
参数(并将password
置为可选参数)
class User{
useName:string;
password?:number|undefined;
//使用{useName:string, password?:number|undefined}约束传入的userData参数
constructor(userData:{useName:string, password?:number|undefined}){
this.useName=userData.useName;
if(userData.password)
this.password=userData.password;
}
}
let u1=new User( {useName:"小猪猪", password:12233} );
let u2=new User( {useName:"大猪猪"} )
console.log(u1);
console.log(u2);
说一下typescript中的泛型
泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
通俗理解:泛型就是解决类 接口 方法的复用性、以及对不特定数据类型的支持
function getData(value:string):string{
return value //只能返回string类型的数据
}
//想要同时返回string和number类型
//1.通常: 代码冗余
function getData1(value:string):string{
return value
}
function getData2(value:number):number{
return value
}
//2.用any(可以解决,但是放弃了类型检查)
function getData(value:any):any{
return value //什么类型都可以
}
//传入什么返回什么。比如传入number类型,必须返回number类型。传入string必须返回string类型。用any就可以不一致。
//泛型,可以支持不特定的数据类型
//要求:传入参数和返回的参数一致
//这里的T指泛型,也可以用任意字母取代,但是前后要一致
function getData<T>(value:T):T{
return value
}
function getData<T>(value:T):T{
return 'xxxx' //错误写法。不能将任何任性分配给T
}
//调用
getData<number>(123); //123
getData<number>('xxx'); //错误写法
//可以调用的时候传一个泛型,返回的时候返回其他的类型(用的不多)
function getData<T>(value:T):any{
return 'xxx'
}
//调用
getData<number>(123); //xxx
getData<string>('xxx'); //xxx
//定义泛型是什么类型,就要传入什么类型的参数
如何在TS中对函数的返回值进行类型约束
ts中函数参数的类型定义
函数的参数可能是一个,也可能是多个,有可能是一个变量,一个对象,一个函数,一个数组等等。
1.函数的参数为单个或多个单一变量的类型定义
function fntA(one, two, three) {
// 参数 "two" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型。
return one + two + three
}
const aResult = fntA(1, '3', true)
修改后:
function fntA(one: number, two: string, three: boolean) {
return one + two + three
}
const aResult1 = fntA(1, '3', true)
// 如果函数的参数为单个或者多个变量的时候,只需要为这些参数进行静态类型下的基础类型定义就行
2.函数的参数为数组的类型定义
function fntB(arr) {
//参数 "arr" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型。
return arr[0]
}
const bResult = fntB([1, 3, 5])
修改后:
function fntB(arr: number[]) {
return arr[0]
}
const bResult1 = fntB([1, 3, 5])
// 如果参数是数组时,只需要为这些变量进行对象类型下的数组类型定义
3.函数的参数为对象的类型定义
function fntC({ one, two }) {
return one + two
}
const cResult = fntC({ one: 6, two: 10 })
修改后:
function fntC({ one, two }: { one: number, two: number }) {
return one + two
}
const cResult1 = fntC({ one: 6, two: 10 })
// 如果参数是对象,只需要为这些变量进行对象类型下的对象类型定义
4.函数的参数为函数的类型定义
function fntD(callback) {
//参数 "callback" 隐式具有 "any" 类型,但可以从用法中推断出更好的类型
callback(true)
}
function callback(bl: boolean): boolean {
console.log(bl)
return bl
}
const dResult = fntD(callback)
修改后:
function fntD(callback: (bl: boolean) => boolean) {
callback(true)
}
function callback(bl: boolean): boolean {
console.log(bl)
return bl
}
const dResult = fntD(callback)
// 如果参数是函数,只需要为参数进行对象类型下的函数类型定义即可
ts中函数返回值的类型定义
当函数有返回值时,根据返回值的类型在相应的函数位置进行静态类型定义即可
返回数字:
function getTotal2(one: number, two: number): number {
return one + two;
}
const total2 = getTotal(1, 2);
// 返回值为数字类型
返回布尔值
function getTotal2(one: number, two: number): boolean {
return Boolean(one + two);
}
const total2 = getTotal(1, 2);
// 返回值为布尔类型
返回字符串
function getTotal2(one: string, two: string): string{
return Bone + two;
}
const total2 = getTotal('1', '2');
// 返回值为字符串
返回对象
function getObj(name: string, age: number): { name: string, age: number } {
return {name,age}
}
getObj('小红',16)
// 返回值为对象
返回数组
function getArr(arr: number[]) :number[]{
let newArr = [...arr]
return newArr
}
getArr([1,2,3,4])
// 返回值为数组
函数返回值为underfinde,仅仅时为了在内部实现某个功能,我们就可以给他一个类型注解void,代表没有任何返回值,
function sayName() {
console.log('hello,world')
}
修改后:
function sayName1(): void {
console.log('无返回值')
}
当函数没有返回值时
// 因为总是抛出异常,所以 error 将不会有返回值
// never 类型表示永远不会有值的一种类型
function error(message: string): never {
throw new Error(message);
}
TS和JS相比有什么区别
TypeScript(TS)和JavaScript(JS)相比,主要的区别体现在以下几个方面:
1. 类型系统:
TypeScript
是一种静态类型的编程语言,它增加了静态类型系统,允许开发者在编写代码时定义变量、参数和返回值的类型。这种类型检查有助于防止类型相关的错误,提高代码的可读性和可维护性。JavaScript
是一种弱类型的编程语言,对使用的数据类型没有严格的要求,变量可以随时改变类型。
2.面向对象:TypeScript
是一种面向对象的编程语言,它支持类、接口和模块等面向对象编程的概念,适合开发大型应用。JavaScript
虽然也可以实现面向对象编程,但通常更被认为是基于对象的脚本语言。
3.编译与解释:TypeScript
需要编译成 JavaScript 才能运行,这提供了更好的类型检查和代码优化。JavaScript
是一种解释型脚本语言,代码不需要编译即可执行。
4.规模和复杂性:TypeScript
更适合用于开发大型的应用,因为大型应用需要模块的集成和易于维护。JavaScript
在小型应用中可能更受欢迎,因为它更轻量且开发效率高。
5.扩展性:TypeScript
是 JavaScript 的超集,包含了 JavaScript 的所有元素,可以载入 JavaScript 代码运行,并扩展了 JavaScript 的语法。JavaScript
本身也有其独特的语法和功能。
6.工具和生态系统:- 由于
TypeScript
的静态类型特性,它更容易与IDE和其他工具集成,提供更好的代码提示和重构功能。 JavaScript
的生态系统非常庞大,有大量的库和框架可供选择。
总的来说,TypeScript
和 JavaScript
各有其优势和适用场景。TypeScript
提供了更强的类型检查和面向对象编程的支持,适合大型、复杂的项目;而 JavaScript
则更轻量、灵活,适合小型、快速迭代的项目。选择哪种语言取决于项目的具体需求和团队的偏好。
当异步操作返回的数据格式不清楚,你如何用TS定义
如果你的函数需要处理多种不同但未知的数据格式,你可以使用泛型来让调用者指定返回数据的类型。
async function fetchData<T>(): Promise<T> {
// 假设这是一个泛型的异步API调用
const response = await someGenericApiCall<T>();
return response;
}
// 调用函数时指定返回数据的类型
fetchData<MyKnownType>().then((data) => {
// 这里你可以安全地访问 MyKnownType 上的所有属性,因为你在调用时指定了它
console.log(data.propertyOfMyKnownType);
}).catch((error) => {
console.error('Error fetching data:', error);
});