JavaScript行为-在TypeScript中思考

2izufjch  于 2022-12-19  发布在  TypeScript
关注(0)|答案(1)|浏览(127)

在继续之前,让我展示一个JavaScript示例:

let a = 5
function fn() {
  console.log(a)
}
fn() // 5
a = 10
fn() // 10

第一个函数调用记录输出5,最后一个函数调用记录输出10。
从这个意义上说,我所考虑的是TypeScript的接口行为合并.一个例子将很好地说明这一点:
接口合并:

interface Example {
  foo: string
}
interface Example {
  bar: string
}

因此,这变成了:

interface Example {
  foo: string
  bar: string
}

现在,让我给你们看一个代表这些想法的例子:

interface Person {
  name: string
}

function myPersonFn() {
  interface Person {
    age: number
  }
  const inPerson: Person = {**name: 'Bhojendra'**, age: 37}
  console.log(inPerson)
}

interface Person {
  address: string
}

const outPerson: Person = {name: 'Rauniyar', address: 'Kathmandu'}
console.log(outPerson)

这会抛出一个错误:(,接口Person是函数作用域。)
键入"{名称:字符串;年龄:number ;}"不能赋给类型"人员"。

  • 对象文本只能指定已知属性,并且类型"Person"中不存在"name"。

现在,让我们尝试扩展它:

interface Person {
  name: string
}
function myPersonFn() {
  // type ScopedPerson = Person & {
  //   age: number
  // }
  interface ScopedPerson extends Person {
    age: number
  }
  const **inPerson**: ScopedPerson = {name: 'Bhojendra', age: 37}
  console.log(inPerson)
}
myPersonFn()
interface Person {
  address: string
}
const outPerson: Person = {name: 'Rauniyar', address: 'Kathmandu'}
console.log(outPerson)

这会抛出一个错误:
类型"{name:}"中缺少属性"address"字符串;年龄:number ;}",但在类型" ScopedPerson "中是必需的。
这实际上是一种类型脚本行为,当Person接口合并接口时,它期望address在其中。
但是我可以要求使用TypeScript,我可以忽略它吗?
那么,如果函数调用结束了呢?

interface Person {
  address: string
}
myPersonFn()

嗯,这使我们认为TypeScript是为我们做的最好的事情,不允许错过address属性。
等等!我在想的是像JavaScript代码一样在第一个代码块中记录a值。嗯,通用的东西可以满足这两种行为?

interface ScopedPerson<T, Optional> extends Person {

我不知道这是否可能?你可能有个主意,如果你明白我的意思?
我想要的是,不要抛出错误,让它编译好函数块里面的这行代码:

const inPerson: ScopedPerson = {name: 'Bhojendra', age: 37}
console.log(inPerson)

很好,我不是在谈论可选的address属性:

interface Person {
  address?: string
}
z0qdvdin

z0qdvdin1#

当Person接口合并接口时,它希望地址在里面,但是我可以请求TypeScript,我可以忽略它吗?
这是不可能的。* 类型声明完全是无序的。* 这就是为什么这是好的:

type A = { a: B }
type B = number

但这也意味着:

interface Person { name: string }
function myPersonFn() {
  interface ScopedPerson extends Person { age: number }
  const inPerson: ScopedPerson = {name: 'Bhojendra', age: 37} // error
}
interface Person { address: string }

还有这个

interface Person { name: string }
interface Person { address: string } // moved this before the function
function myPersonFn() {
  interface ScopedPerson extends Person { age: number }
  const inPerson: ScopedPerson = {name: 'Bhojendra', age: 37} // error
}

在各方面都是100%相同的。
所以Typescript不可能知道你想要一个接口的一部分,而不是另一个,它们没有不同的名称或标识符,并且类型本身根本没有记录表明这是合并的。
如果你想推理这种类型的子集,那么它们需要是独立的类型。
例如:

// This is just a piece of a `Person`, so call it `PersonName`.
interface PersonName { name: string }

// Maybe create another type for only a persons address
interface PersonAddress { address: string }

// Then create a full person from its pieces
interface Person extends PersonName, PersonAddress {}

function myPersonFn() {
  interface ScopedPerson extends PersonName { age: number }
  const inPerson: ScopedPerson = {name: 'Bhojendra', age: 37} // fine
}

这里PersonName只是name属性,ScopedPerson添加了age,因为它只在该函数内部使用,Person扩展了PersonName并添加了address
见Playground

相关问题