构造对象属性的联合类型
在单页面项目中,我们基本上都会定义一个存储路由的数组,像这样
const routes = [
{
path: '/home',
component: Home,
},
{
path: '/login',
component: Login,
},
//...
]
然后我们在使用的时候,会像这样去执行路由跳转,比如
this.props.push('/home')
但是当我们路由变得比较多的时候,写在这里的字符串就很容易出错,我们希望能得到具体的提醒,所以我们需要写一个工具类来获取路由数组所有路径构成的联合类型,像这样
const routes= [
{
path: '/home',
component: Home,
},
{
path: '/login',
component: Login,
},
//...
] as const
type IRoute = typeof routes[number]['path']
// IRoute ==> '/home' | '/login'
as const 是TS的一种语法,它可以让目标对象在被解析式,不往上方扩展,比如“1”不能被解析为string,它只会被解析为类型“1”,之后我们想在状态对象上添加其他的类型,也不需要遵循相同的值类型了。
推断JSON.Prase序列化之后的类型
在请求接口时,拿回来的数据,一般都是序列化之后的字符串,我们需要先进行反序列化操作,然后再将获取到的数据进行处理,但是,我们在JSON.prase之后,得到的数据并不能推断出具体的类型
当然这个时候可以使用类型断言,让编译器知道变量的类型
但我们其实不希望每次使用JSON.parse都手动的去加一个类型断言,毕竟有的时候写类型文件和使用方法的不是同一个人,我们还是希望能写一个接口来统一推断,所以我们可以这样写
type json<T> = string & T
interface JSON {
parse<T>(text: json<T>, reviver?: (key: any, value: any) => any): T;
stringify<T>(value: T, replacer?: (key: string, value: any) => any, space?: string | number): json<T>;
stringify<T>(value: T, replacer?: (number | string)[] | null, space?: string | number): json<T>;
}
之后我们就能得到准确的类型推断
type Person = {
name: string;
age: number;
};
const role: Person = {
name: 'jj',
age: 20,
};
const str: json<Person> = JSON.stringify(role);
const x = JSON.parse(str);
为配置文件定义类型
一般情况下,我们的项目都会有多个环境的配置文件,比如.dev,.pro,.release这些,但是里面配置对象的键值都是一样的,像这样。
proConfig = {
//....
url:...
api:...
corpid:...
}
devConfig = {
//....
url:...
api:...
corpid:...
}
releaseConfig = {
//....
url:...
api:...
corpid:...
}
但是有时候,我们根据需要去测试环的境配置文件添加一个变量,可能就忘记了去正式和发布环境添加,导致之后打包上线出问题,这个时候我们应该为他们定义一个相同类型,来避免这种情况。
我们可以直接定义一个对应的type,然后赋给三个对象
type IConfig = {
//....
url:string
api:string
corpid:string
}
但是这样有一个问题,就是后续我们如果加新的变量,就需要一直修改类型,显然这很麻烦,所以我们可以根据一个配置文件,来逆向的推导出类型,以dev为例子
const devConfig = {
url: 'xxx',
cropid: '123',
};
type IConfigUtil<T extends object> = {
[P in keyof T]: T[P];
};
type IConfig = IConfigUtil<typeof devConfig>;
写在最后
感谢你能看到这里,本文记录了几个关于TS的优化,其实相关的还有很多,后续会陆陆续续的更新,希望对你有所帮助,如果你发现了问题和更好的解决方案,欢迎留言一起讨论