typescript type interface区别(typescript type interface)
大家好,关于typescript type interface区别很多朋友都还不太明白,不过没关系,因为今天小编就来为大家分享关于typescript type interface的知识点,相信应该可以解决大家的一些困惑和问题,如果碰巧可以解决您的问题,还望关注下本站哦,希望对各位有所帮助!
type 和 interface的区别
大家使用 typescript总会使用到 interface和 type,官方规范稍微说了下两者的区别
An interface can be named in an extends or implements clause, but a type alias for an object type literal cannot.
An interface can have multiple merged declarations, but a type alias for an object type literal cannot.
但是没有太具体的例子。
明人不说暗话,直接上区别。
相同点
都可以描述一个对象或者函数
interface
interface User{
name: string
age: number
}
interface SetUser{
(name: string, age: number): void;
}
type
type User={
name: string
age: number
};
type SetUser=(name: string, age: number): void;
拓展(extends)与交叉类型(Intersection Types)
interface可以 extends,但 type是不允许 extends和 implement的,但是 type缺可以通过交叉类型实现 interface的 extend行为,并且两者并不是相互独立的,也就是说 interface可以 extends type, type也可以与 interface类型交叉。
虽然效果差不多,但是两者语法不同。
interface extends interface
interface Name{
name: string;
}
interface User extends Name{
age: number;
}
type与 type交叉
type Name={
name: string;
}
type User= Name&{ age: number};
interface extends type
type Name={
name: string;
}
interface User extends Name{
age: number;
}
type与 interface交叉
interface Name{
name: string;
}
type User= Name&{
age: number;
}
不同点
type可以而 interface不行
type可以声明基本类型别名,联合类型,元组等类型
//基本类型别名
type Name= string
//联合类型
interface Dog{
wong();
}
interface Cat{
miao();
}
type Pet= Dog| Cat
//具体定义数组每个位置的类型
type PetList= [Dog, Pet]
type语句中还可以使用 typeof获取实例的类型进行赋值
//当你想获取一个变量的类型时,使用 typeof
let div= document.createElement('div');
type B= typeof div
其他骚操作
type StringOrNumber= string| number;
type Text= string|{ text: string};
type NameLookup= Dictionary<string, Person>;
type Callback<T>=(data: T)=> void;
type Pair<T>= [T, T];
type Coordinates= Pair<number>;
type Tree<T>= T|{ left: Tree<T>, right: Tree<T>};
interface可以而 type不行
interface能够声明合并
interface User{
name: string
age: number
}
interface User{
sex: string
}
/*
User接口为{
name: string
age: number
sex: string
}
*/
TypeScript 和 JavaScript 的区别
TypeScript和 JavaScript是目前项目开发中较为流行的两种脚本语言,我们已经熟知 TypeScript是 JavaScript的一个超集。JavaScript和 TypeScript的主要差异:
1、TypeScript可以使用 JavaScript中的所有代码和编码概念,TypeScript是为了使 JavaScript的开发变得更加容易而创建的。例如,TypeScript使用类型和接口等概念来描述正在使用的数据,这使开发人员能够快速检测错误并调试应用程序
2、TypeScript从核心语言方面和类概念的模塑方面对 JavaScript对象模型进行扩展。
3、JavaScript代码可以在无需任何修改的情况下与 TypeScript一同工作,同时可以使用编译器将 TypeScript代码转换为 JavaScript。
4、TypeScript通过类型注解提供编译时的静态类型检查。
5、TypeScript中的数据要求带有明确的类型,JavaScript不要求。
6、TypeScript为函数提供了缺省参数值。
7、TypeScript引入了 JavaScript中没有的“类”概念。
8、TypeScript中引入了模块的概念,可以把声明、数据、函数和类封装在模块中。
一道3 层的 typescript 面试题,你能答到第几层
一道 3层的 typescript面试题,你能答到第几层?
这道题有 3个层次,我们一层层来看。
第一层的要求是这样的:
实现一个 zip函数,对两个数组的元素按顺序两两合并,比如输入 [1,2,3], [4,5,6]时,返回 [[1,4], [2,5],[3,6]]
这层就是每次各从两个数组取一个元素,合并之后放到数组里,然后继续处理下一个,递归进行这个流程,直到数组为空即可。
functionzip(target, source){
if(!target.length||!source.length)return[];
const[one,...rest1]= target;
const[other,...rest2]= source;
return[[one, other],...zip(rest1, rest2)];}
结果是对的
也是直接 function声明函数类型和 interface声明函数类型然后加到变量类型上两种。
因为具体元素类型不知道,所以用 unknown。
这里可能会问 any和 unknown的区别:
any和 unknown都可以接收任何类型:
但是 any也可以赋值给任何类型,但 unknown不行。
这里只是用来接收其他类型,所以 unknown比any更合适一些,更安全。
这一层也是比较基础的 ts语法,第三层就上了难度了:
用类型编程实现精确的类型提示,比如参数传入 [1,2,3], [4,5,6],那返回值的类型要提示出 [[1,4], [2,5],[3,6]]
这里要求返回值类型是精确的,我们就要根据参数的类型来动态生成返回值类型。
也就是这样:
声明两个类型参数 Target、Source,约束为 unknown[],也就是元素类型任意的数组类型。
这俩类型参数分别是传入的两个参数的类型。
返回值通过 Zip计算得出。
然后要实现 Zip的高级类型:
传入的类型参数分别是两个数组类型,我们同样要从中提取出每个元素合并到一起。
提取元素可以用模式匹配的方式:
所以这个类型就可以这样定义:
typeZip<Oneextendsunknown[], Otherextendsunknown[]>=
Oneextends[infer OneFirst,...infer Rest1]
? Otherextends[infer OtherFirst,...infer Rest2]
? [[OneFirst, OtherFirst],...Zip<Rest1, Rest2>]
: []
: [];
分别提取两个数组的第一个元素,构造成新数组。然后对剩下的数组递归进行这样的处理,直到数组为空。
这样就实现了我们想要的高级类型:
但你把它作为返回值加到函数上会报错:
因为声明函数的时候都不知道参数是啥,自然计算不出 Zip<Target, Source>的值,所以这里会类型不匹配:
那怎么办呢?
可以用函数重载解决:
ts支持函数重载,可以写多个同名函数的类型的类型定义,最后写函数的实现,这样用到这个函数的时候会根据参数的类型来匹配函数类型。
我们用了类型编程的那个函数通过这种方式写就不会报错了。
我们使用下看看:
咋返回值的类型不对呢?
其实这时候匹配的函数类型是对的,只不过推导出的不是字面量类型。
这时候可以加个 as const。
但是加上 as const会推导出 readonly [1,2,3]
这样类型就不匹配了,所以要在类型参数的声明上也加上 readonly:
但这样 Zip函数的类型又不匹配了。
难道要把所有用到这个类型的地方都加上 readonly么?
不用,我们 readonly的修饰去掉不就行了?
Type有内置的高级类型 readonly:
可以把索引类型的每个索引都加上 readonly修饰:
但没有提供去掉 readonly修饰的高级类型,我们可以自己实现一下:
用映射类型的语法构造个新索引类型,加上个-readonly就是去掉 readonly修饰的意思。
有的同学可能问了,数组类型也是索引类型么?
是,索引类型是聚合多个元素的类型,所以对象、数组、class都是。
所以我们把它用在数组上自然也是可以的:
(准确来说叫元组,元组是元素个数固定的数组)
那我们只要在传入 Zip之前,用 Mutable去掉 readonly就可以了:
再来试一下:
大功告成!现在返回值的类型就对了。
但还有个问题,如果不是直接传入字面量,是推导不出字面量类型的,这时候貌似就不对了:
可我们不都声明重载类型了么?
如果推导不出字面量类型,应该匹配这个呀:
但实际上它匹配的还是第一个:
这时候其实只要调换下两个函数类型的顺序就可以了:
这时字面量参数的情况依然也是对的:
为什么呢?
因为重载函数的类型是从上到下依次匹配,只要匹配到一个就应用。
非字面量的情况,类型是 number[],能匹配 unknown[]的那个类型,所以那个函数类型生效了。
而字面量的情况,推导出的是 readonly [1,2,3],带有 readonly所以不匹配 unknown[],继续往下匹配,就匹配到了带有类型参数的那个函数类型。
这样两种情况就都应用了合适的函数类型。
全部代码是这样的:
typeZip<Oneextendsunknown[], Otherextendsunknown[]>= Oneextends[
infer OneFirst,
...infer Rest1
]
? Otherextends[infer OtherFirst,...infer Rest2]
? [[OneFirst, OtherFirst],...Zip<Rest1, Rest2>]
: []
: [];
typeMutable<Obj>={
-readonly [Keyinkeyof Obj]: Obj[Key];
};
functionzip(target: unknown[], source: unknown[]):unknown[];
functionzip<Targetextendsreadonlyunknown[],Sourceextendsreadonlyunknown[]>(
target: Target,
source: Source
):Zip<Mutable<Target>,Mutable<Source>>;
functionzip(target: unknown[], source: unknown[]){
if(!target.length||!source.length)return[];
const[one,...rest1]= target;
const[other,...rest2]= source;
return[[one, other],...zip(rest1, rest2)];
}
constresult= zip([1,2,3]asconst, [4,5,6]asconst);
constarr1= [1,2,3];
constarr2= [4,'5',6];
constresult2= zip(arr1, arr2);
今天我们做了一道综合的 ts面试题,一共有三层:
第一层实现 js的逻辑,用递归或者循环都能实现。
第二层给函数加上类型,用 function声明类型和 interface声明函数类型两种方式,参数和返回值都是 unknown[]。
第三层是用类型编程实现精准的类型提示,这一层需要拿到参数的类型,通过提取元素的类型并构造出新的数组类型返回。还要通过函数重载的方式来声明类型,并且要注意重载类型的声明顺序。
as const能够让字面量推导出字面量类型,但会带有 readonly修饰,可以自己写映射类型来去掉这个修饰。
其实这也是我们学习 ts的顺序,我们先要能把 js逻辑写出来,然后知道怎么给函数、class等加 ts类型,之后学习类型编程,知道怎么动态生成类型。
其中类型编程是 ts最难的部分,也是最强大的部分。攻克了这一层,ts就可以说学的差不多了。
好了,本文到此结束,如果可以帮助到大家,还望关注本站哦!