是时候终结关于ts中type和interface之争了

8 阅读4分钟

typeinterface之争其实很简单。

比如有如下函数定义:

function fn (props: Props) {}

适合使用interface的场景

如果这个props只需要满足几个条件即可,比如只要是任意包含name字段的Object都行,例如:

interface Props {
  name: string
}

function fn (props: Props): string {
  return 'hello ' + props.name
}

type Human = {
  name: string,
  age: number
}

interface Dog {
  name: string,
  color: string
}

const h1: Human = { name: '张三', age: 18 }
const d1: Dog = { name: '大黄', color: 'yellow' }

console.log(fn(h1))
console.log(fn(d1))

此时fn参数不管是,typeHuman,还是interfaceDog,只要包含了name字段都可以。

适合使用type的场景

还是用刚才fn函数举例子,如果props要求传入的参数必须满足全部的条件,即必须是指定的类型,例如:

type Props = {
  name: string,
  age: number
}

function fn (props: Props): string {
  return 'hello ' + props.name
}

console.log(fn({ name: '张三', age: 18 }))

const p1: Props = { name: '李四', age: 20 }
console.log(fn(p1))

此时只要传入的参数不符合Props定义的任何字面和非字面Object都会报错,比如非字面量报错:

/**
 * 报错:
 * 类型“{ name: string; }”的参数不能赋给类型“Props”的参数。  
 * 类型 "{ name: string; }" 中缺少属性 "age",但类型 "Props" 中需要该属性。ts(2345)
 * [test.ts(3, 3): ]()在此处声明了 "age"。
 */
console.log(fn({ name: '张三' }))

字面量报错:

/**
 * 类型“Dog”的参数不能赋给类型“Props”的参数。
 * 类型 "Dog" 中缺少属性 "age",但类型 "Props" 中需要该属性。ts(2345)
 * test.ts(3, 3): 在此处声明了 "age"。
 * const dog: Dog
 */
interface Dog {
  name: string,
  color: string
}
const dog: Dog = { name: '大黄', color: 'yellow' }
console.log(fn(dog))

typescript对我的意义

在我看来,ts的出现解决的最大痛点是js在开发维护的过程中,降低重构的心智负担,项目越来越大之后,有的复杂function时间一久,你自己都忘了怎么用了,只能去全局搜索相关用例。

如果要重构修改的话,就更头疼了,保不齐改漏了什么地方,测试又没覆盖到,bug就这样出现了,有bugbug这倒也不是啥大事,主要是重构和修改的过程中心智负担很大,生怕漏了什么。

js项目中,如果你写了一个底层库,以往的团队合作,别人要使用你的库,或者你要使用别人的库,只能是:写文档看文档、写jsdoc、自己看代码实现、自己看代码用例,不管是哪个场景都有不小的心智负担,而有了ts的话,不敢说完美解决,但至少能在一些场景下减轻不少心智负担。比如一个有着复杂参数函数的传参,基于vscode的代码提示,能很清晰的知道参数该怎么传,返回值是啥,等等。

typescript与jsdoc

jsdoc确实可以定义类型,但比起ts还是要繁琐不少,并且没有足够强制性的约束力,ts在编译时可以检查报错,不过jsdoc也是有一些应用场景的,比如仅需要少了定义描述介入的时候,对老项目的补充维护之类的。还是那句话,对待任何技术,永远不要二极管,得根据具体场景做选择才是最合理的。

结论

type是要求必须是该type字面定义满足该type定义,interface任意字面定义非字面定义满足该interface定义即可。

其实真正接触过面向对象思想的人(仅学过的不算),都能理解typeinterface的区别和何时该用哪个。

当初我初学的时候也不理解,既然有各种class定义了,为何还需要interface,觉得interface啥都不做,就在哪里定义一下,显得很多余,后来接触了Android开发后,发现有的函数方法,可以接受的参数只要满足某一个interface的定义就可以传入,极大的方便了开发,降低设计成本。

也可以说是存在即可合理吧,按需按场景决定用哪个,之前看过有帖子说无脑梭其中一个就行了,我觉得太二极管了,这不应该是程序员该有的思维,还是应该结合多方面因素综合考虑哪个更合适更好一些。

还有一些人觉得,这是把java那一套丑思想给硬搬过来套在js上了,对于这类人,我只能说尊重祝福,希望你永远不会有需要typescript的时候。