我在项目中定义了两个 interface
,
interface person{
name:string
age:number
}
interface animal {
food:string
kind:string
}
接下有个函数是处理这两个类型的
function test(some:person|animal){
// TODO:
// 我想在这里判断 some 具体是什么然后分别处理
// 期望的伪代码:
if(some 的类型=== person){}
else if(some 的类型=== animal)
}
我自己想到了用 js
的 is 关键词去判断某个属性是否存在来具体区分这两个 interface
,但是这样好像已经到了 js
的层面了。
问题:在 TS 层面有没有可以实现的方式呢?
ts 的 interface 在编译成 js 时会被删除,所以无法在运行时使用 interface 来做判断。
interface person{
name:string
age:number
}
interface animal {
food:string
kind:string
}
function test(some:person|animal){
if('name' in some) {
some
// ?^ person
}
if('food' in some) {
some
// ?^ animal
}
}
话先说在头,其实TS官网教程类型收窄这章里,讲到typeof
检查、in
检查,已经能做到大部分情况的类型收窄了,一般业务开发没必要过于苛求运行时的检查。像题主的例子里,if ('name' in some) {}
和if ('food' in some) {}
就能自动收窄Person
和Animal
了。除非你对类型检查有很极致的追求。
以下正文。
interface
和type
属于编译期行为,编译结束后是不存在的,所以你在JS里是无法直接使用interface
来判断类型。
解决办法,一种是写谓词函数(predicate)来手动检查。这种函数的返回值是value is SomeType
形式。
interface Person {
name: string
age: number
}
interface Animal {
food: string
kind: string
}
// 判断一个对象是否Person
function isPerson(o: unknown): o is Person {
const obj = o as Partial<Person> | null | undefined
if (
typeof obj?.name === 'string'
&&
typeof obj?.age === 'number'
) {
return true
} else {
return false
}
}
// 判断一个对象是否Animal
function isAnimal(o: unknown): o is Animal {
const obj = o as Partial<Animal> | null | undefined
if (
typeof obj?.food === 'string'
&&
typeof obj?.kind === 'number'
) {
return true
} else {
return false
}
}
function test(some: Person | Animal) {
if (isPerson(some)) {
// 现在some是Person
console.log(some)
}
if (isAnimal(some)) {
// 现在some是Animal
console.log(some)
}
}
看代码你也发现,这样手写predicate
非常繁琐,而且容易有遗漏。
所以有一个工具库io-ts可以代替繁琐的工作。
import * as t from 'io-ts'
// 先定义运行时检查工具
const User = t.type({
name: t.string,
age: t.number
})
// 转化为type
type User = t.TypeOf<typeof User>
// 以下同上
const Animal = t.type({
food: t.string,
kind: t.string
})
type Animal = t.TypeOf<typeof Animal>
function test(some: User | Animal) {
if (User.is(some)) {
console.log('现在some是Person', some)
}
if (Animal.is(some)) {
console.log('现在some是Animal', some)
}
}
test({ name: 'tom', age: 3 })
test({ kind: 'cat', food: 'fish' })
在TS里,class
既是type也是value,所以,还有一种方法,就是干脆用class
创建对象,然后用instanceof
检查原型链判断类型
class Person {
name: string
age: number
constructor(init: Person) {
Object.assign(this, init)
}
}
class Animal {
food: string
kind: string
constructor(init: Animal) {
Object.assign(this, init)
}
}
function test(some: Person | Animal) {
if (some instanceof Person) {
console.log('现在some是Person', some)
}
if (some instanceof Animal) {
console.log('现在some是Animal', some)
}
}
// 必须要用构造函数来创建class实例
test(new Person({ name: 'tom', age: 3 }))
test(new Animal({ kind: 'cat', food: 'fish' }))
这就是很经典的OOP
开发方式。如果此前习惯传统JS匿名对象的写法,可能需要一定时间才能适应。
在 TypeScript 中,你通常会使用类型守卫(Type Guards)来在函数体内判断参数的类型。类型守卫是一种表达式,它执行运行时检查并返回一个类型信息给 TypeScript 的类型系统。
你可以通过自定义类型守卫函数或者使用 in
关键字配合类型断言来实现这一点。但是,请注意,TypeScript 的类型系统只在编译时存在,运行时并不包含类型信息,所以类型守卫实际上是执行一些运行时的检查来模拟类型信息。
下面是一个使用 in
关键字和类型断言的示例:
interface Person {
name: string;
age: number;
}
interface Animal {
food: string;
kind: string;
}
function isPerson(some: any): some is Person {
return 'name' in some && 'age' in some;
}
function isAnimal(some: any): some is Animal {
return 'food' in some && 'kind' in some;
}
function test(some: Person | Animal) {
if (isPerson(some)) {
// 在这个分支中,TypeScript 知道 some 是 Person 类型
console.log(some.name, some.age);
} else if (isAnimal(some)) {
// 在这个分支中,TypeScript 知道 some 是 Animal 类型
console.log(some.food, some.kind);
}
}
// 示例使用
const personObj: Person = { name: 'Alice', age: 30 };
const animalObj: Animal = { food: 'meat', kind: 'dog' };
test(personObj); // 输出 Alice 30
test(animalObj); // 输出 meat dog
在这个例子中,isPerson
和 isAnimal
函数是自定义的类型守卫。它们接收一个 any
类型的参数,并返回一个布尔值,表示参数是否符合 Person
或 Animal
类型。通过返回 some is Person
或 some is Animal
,TypeScript 的类型系统会理解在这些函数内部的条件分支中,some
的确切类型是什么。
这样,你就可以在 test
函数内部安全地使用 some
对象的特定属性,而不用担心类型错误了。
本文向大家介绍JavaScript如何判断input数据类型,包括了JavaScript如何判断input数据类型的使用技巧和注意事项,需要的朋友参考一下 这篇文章主要介绍了JavaScript如何判断input数据类型,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在HTML中接收用户输入信息一般都会用到<input/>。我今天本来想实现一个功
本文向大家介绍Javascript如何判断数据类型和数组类型,包括了Javascript如何判断数据类型和数组类型的使用技巧和注意事项,需要的朋友参考一下 这么基础的东西实在不应该再记录了,不过嘛,温故知新~就先从数据类型开始吧 js六大数据类型:number、string、object、Boolean、null、undefined string: 由单引号或双引号来说明,如"string" nu
让我们分析下面的代码片段: 以上代码不会引发任何错误。我希望它会抛出构造函数调用,在这里我传递5。 似乎构造函数的参数被推断为,其中,静态地很容易发现我将其分配给。 问题是:TypeScript在这里允许,或者换言之,被推断为,而在这种情况下,很明显它必须是一个字符串,这有什么特殊的原因吗? 我知道我可以做另一个这样的类定义: 但这里我指定了参数类型,所以这里没有推断。我也可以这样做: 也不会有任
函数名称:判断数据类型 函数名称:判断数据类型 函数方法 bool = type(str) 参数 必填 说明 str 是 需要判断的数据 返回值 说明 bool 数据类型:"number"、"string"、"boolean"、"table"、"function"、"thread"、"userdata" 函数用例 num = 111 str = tostring(num) dialog("转换后的
在写单元测试中,我想抽象一个通用的函数,避免重复书写。函数的定义如下: 但是我不知道如果建立 fn 函数参数的类型和 source 类型之间的联系。 请问要怎么写才可以让 source 的类型等于 fn 参数类型的数组?
我有一个类,它有一些属性/方法,返回最初通过构造函数传递的值: 人们建议用泛型作为打字稿的等价物: 现在我有了一个子类,它调用超类的构造函数并传递以下选项: TypeScript编译器对此不满意,希望通过类型扩展Base类。但是我有两次信息,在超级呼叫和扩展符号中。什么是正确的ts语法来解决我的问题? (键入脚本中的代码)