TS有什么优点和缺点,适应场景是什么
静态类型
有类型错误,编译时就报错(而非运行时)
智能提示,提高开发效率和稳定性
缺点:
有一定学习成本
某些情况下,类型定义过于混乱,可读性不好
类型设计过于灵活和松散,且有“万恶”的any
应用不规范,则变成“anyscript”
适用场景:
大型项目,业务复杂,维护人员多
逻辑性比较强的代码,需要类型更稳固
组内要有至少一个懂TS 的技术leader负责把控代码规范
TS的基础类型有哪些,数组和元组有什么区别
基础类型:
boolean
symbol
number
undefined
string
null
其他类型:
数组 Array和元组Tuple
枚举
对象和函数(一般是自定义的)
//数组单一类型
const arr1:number[]=[1,2,34,4]
const arr2:Array<number>=[10,20,30] //泛型
//元祖 多个类型
const x:[string,number]=['a',1]
//枚举(本质就是JS对象)
enum Color{
Red,
Green,
Blue
}
const c:Color=Color.Blue
//对象和函数
interface User{
name:string,
age:number,
sayHi:(a:string)=>{}
}
const user:User={
name:'aa',
age:90,
sayHi(a){return a}
}
any void never unknown 区别
any : 不进行类型检查 比较危险的情况
void : 和 any 相反,没有类型 一般配合函数一起使用 function f1(): void {}
never : 永远不存在的类型 function err(message:string):never{throw new Error(message)}
unknown :未知类型 更加安全的any
// as 手动类型转换,告诉 TS 编译器:我知道 b的类型,我对安全负责
const b: unknown = 100
;(b as string).length
TS 访问修饰符有哪几个?
public (默认)-全部可访问
protected - 自己和派生类可访问 派生类就是继承自己的类
private - 只有自己可访问
代码演示
class Person {
public name: string = ''
protected age: number = 0
private girlFriend: string
constructor(name: string, age: number) {
this.name = name
this.age = age
this.girlFriend = '小张'
}
}
class Employee extends Person {
constructor(name: string, age: number) {
super(name, age)
}
public getInfo() {
console.log(this.name)
console.log(this.age)
}
}
const x = new Employee('x', 200)
console.log(x.name)
//面向对象三大要点:继承 封装 多态(函数重载)
TS私有属性# 和 private 有什么区别
# 属性,不能在构造函数参数中定义
private 属性,可通过as any 强制获取,但#属性不行
class Person {
#salary: number
constructor(private name: string, salary: number) {
this.#salary = salary
}
print() {
console.log(this.#salary)
console.log(this.name)
}
}
const p = new Person('x', 5000)
console.log((p as any).name)
TS中type和interface有何区别,如何选择
type和interface的共同点:
都可以描述一个对象结构
都可以被class实现
都可以被扩展
interface UserInfo {
name: string
age: number
getName: () => string
}
const userInfo: UserInfo = {
name: 'zs',
age: 90,
getName() {
return 'sss'
}
}
console.log(userInfo.age)
//使用type
type UserType = {
name: string
age: number
getName: () => string
}
const userType: UserType = {
name: 'zs',
age: 90,
getName() {
return 'ttt'
}
}
class UserClass implements UserInfo {
name = 'ccc'
age = 20
getName() {
return 'aaa'
}
}
class UserTypeCLass implements UserType {
name = 'ccc'
age = 20
getName() {
return 'aaa'
}
}
type 和 interface 不同点
type 可以声明基础类型
type 可以使用联合类型 交叉类型
type 可以通过 typeof赋值
//type 可以定义基础类型 interface不行
type name = string
type list = Array<string>
总结: type 和 interface 如何选择
初衷:type 定义类型关系,interface 定义数据结构;
但实际使用时,很多时候会模糊不清,没有明确的界限
我的建议:优先使用interface,再使用type(简单明了)
type 和 interface 如何扩展属性?
interface 可以合并重名声明 type 不可以
interface myUser {
name: string
}
interface myUser {
age: number
}
//使用
const myuser: myUser = { name: 'zhangsan ', age: 90 }
console.log(myuser.age)
interface 扩展interface / type
interface User1 {
name: string
}
interface User2 extends User1 {
age: number
}
const u2: User2 = { name: 'zhangsan ', age: 90 }
//type 也可以通过extends扩展
type User1 = {
name: string
}
interface User2 extends User1 {
age: number
}
const u2: User2 = { name: 'zhangsan ', age: 90 }
// type 扩展type / interface
type User3 = {
name: string
}
type User4 = User3 & {
age: number
}
const u3: User4 = { name: 'zhangsan ', age: 20 }
//interface type相互扩展
interface User3 {
name: string
}
type User4 = User3 & {
age: number
}
const u3: User4 = { name: 'zhangsan ', age: 20 }
console.log(u3)
【附】type 和 interface 的问题,是 TS 设计问题
初衷是好的,但实际使用时引起“选择困难症”引来社区争吵
就像 Vue3 的 ref和 reactive(再对比 React的state和 ref )
好的设计,应该简单明确,而不是设计混乱并说是你不会用
TS 的泛型 Generics 是什么?
//泛型定义到函数
function fn<T>(arg: T): T {
return arg
}
const x = fn<number>(100)
//定义数组
const list: Array<number> = [10, 30]
//定义接口
interface userP {
name: string
age: number
}
const userp: Array<userP> = [{ name: 'xxx', age: 88 }]
//多个类型
function fn1<T, U>(a: T, b: U) {
console.log(a, b)
}
fn1<string, number>('x', 10)
//定义在class
class SomeClass<T> {
name: T
constructor(name: T) {
this.name = name
}
getName(): T {
return this.name
}
}
const s1 = new SomeClass<string>('xxx')
const s2 = new SomeClass<number>(888)
//定义在 type
function fn<T>(arg: T): T {
return arg
}
const myFn1: <U>(arg: U) => U = fn
// 定义在接口
interface F2<T> {
(arg: T): T
}
const myFn2: F2<number> = fn
泛型的使用
// 泛型 可以传入任何类型
interface UserPerson {
name: string
age: number
}
const u = fn<UserPerson>({ name: 'xx', age: 10 })
console.log(u, 'uuuuu')
//泛型 可以当做任何类型来使用
function fn3<T>(arg: Array<T>) {
console.log(arg)
}
fn3<string>(['x'])
fn3<number>([20, 30])
// 泛型的扩展属性
interface F5 {
length: number
}
function fn4<T extends F5>(arg: T) {
console.log(arg.length)
}
fn4<string>('xxxx')
fn4<number[]>([10, 23])
总结泛型
泛型Generics,是为了通用性和扩展性
泛型定义:函数class interface type
泛型使用:传入任何类型,当做任何类型,扩展其他属性
TS中交叉类型和联合类型是什么
交叉类型
多个类型合并为一个类型T1 & T2 & T3
interface U1 {
name: string
age: number
}
interface U2 {
city: string
age: number
}
//交叉类型
type UserType1 = U1 & U2
//可获取U1 U2的所有属性(并集)
interface U1 {
name: number
city: string
}
interface U2 {
name: string
age: number
}
//如果属性类型冲突了 那该属性类型是never
//交叉类型(整合U1 U2的所有属性 并集)
type UserType1 = U1 & U2
const userTest: UserType1 = { name: 'x', city: 'beijing', age: 20 } //注意这里
要解决上面的问题 需要主动去规避
interface U1 {
name: string
city: string
}
interface U2 {
name: string
age: number
}
//交叉类型(整合U1 U2的所有属性 并集)
type UserType1 = U1 & U2
const userTest: UserType1 = { name: 'x', city: 'beijing', age: 20 }
基础类型不能交叉 返回never 没有任何意义
type Tx = string & number //返回never 没有任何意义
联合类型
联合多个类型 T1·| T2|T3 ,
一种“或”的关系
**基础类型可以联合**
interface U1 {
name: string
city: string
}
interface U2 {
name: string
age: number
}
//在函数使用
function fnT(): U1 | U2 {
return {
name: 'x',
age: 90
}
}
type Tx = string | number
const xxx: Tx = 100
//错误写法
function fn9(a: string | number){
console.log(a.length) //这里会报异常
}
TS中有哪些特殊符号,分别是什么意思-part1
TS 特殊符号? ?. ?? ! _ &| #
? 表示可选
interface PersonInfo {
name?: string
age: number
}
const P: PersonInfo = { age: 888 }
function Perosns(a: number, b?: number) {
console.log(a, b)
}
Perosns(10) // 10 undefined
?. 表示可选链
const infoD: any = {
info: {
city: '北京'
}
}
const city = infoD?.info?.city
?? 表示空值合并运算符(只有左侧是null或者undefined 才会返回右侧 补齐 ||)
const user2: any = {
name: '张三',
index: 0
}
const n1 = user2.name ?? '暂无'
const n2 = user2.name || '暂无'
const index1 = user2.index ?? '暂无index'
const index2= user2.index || '暂无index'
console.log(index1 ,index2) // 0 '暂无index'
! 表示非空断言操作符号
function fun(a?: string) {
return a!.length // 加! 表示你已经知道了a不会是undefined
}
_ 表示数字分隔符
const millon = 100_000_111
总结一下
? 可选属性/参数
! 非空断言符
?.可选链
_ 数字分隔符
?? 空值合并运算符
其他 & | #
TS常见的工具类型有哪些
Partial<T>
interface CityInfo {
name: string
age: number
city: string
}
//使用 Partial
const u: Partial<CityInfo> = { name: 'x', city: 'dkd' }
//类似于这样的可选结构
interface CityInfo {
name?: string
age?: number
city?: string
}
Required<T>
interface CityInfo {
name: string
age: number
city: string
}
// Required 必填 少一个都不行
const u: Required<CityInfo> = { name: 'x', city: 'dkd', age: 99 }
Pick<T,K> 选取一个或者多个
interface CityInfo {
name: string
age: number
city: string
}
const u: Pick<CityInfo, 'name' | 'age'> = { name: 'x', age: 99 }
//使用
type CityType = Pick<CityInfo, 'name'>
const city1: CityType = { name: 'ddd' }
Omit<T,K> 剔除几个属性 忽略几个
//剔除 city属性
type CityType2 = Omit<CityInfo, 'city'>
const city2: CityType2 = { name: 'ddd', age: 222 }
ReadOnly<T> 设置每个属性为只读
type CityType3 = Readonly<CityInfo>
const city3: CityType3 = { name: 'xx', age: 90, city: 'ddd' }
//CityType3.name='333' 这里就报错了
const 和 readonly 区别
const 和 readonly 区别
const 定义单独的变量
readonly 定义属性
TS如何扩展window属性?
declare interface Window {
test: string
}
Window.test='xxx'
TS 如何扩展一个对象的属性?
interface Obj {
[key: string]: any
}
const obj: Obj = {
a: 10,
b: 20
}
obj.d = 30
obj.c = '90'
TS中如何定义第三方模块的类型?
现在很多插件都是直接用TS 开发的,本身包含了类型定义
常见的第三方插件,都有 @types/xxx包,安装即可使用
其他的,可通过declare module定义类型