在Typescript中,我有一个接口MyInterface
定义如下:
interface MyInterface {
hello: string
}
使用它来定义对象不允许我包含接口未描述的属性。下面会产生一个错误,指示不允许属性what
,因为它未在MyInterface
中定义:
const testObject: MyInterface = {
hello: 'world',
what: 'is going on',
^^^^^^^^^^^^^^^^^^^
}
但是,将其用作 promise 结果类型允许我返回未在MyInterface
中定义的属性;以下内容不会产生错误:
const testPromise: Promise<MyInterface> = Promise.resolve({
hello: 'world',
what: 'is going on',
});
期望在第二个代码段中发生相同的错误是否合理?如果没有,有没有办法像对象赋值示例中那样使承诺的返回类型严格?
你所说的"严格"通常被称为"精确类型"。精确对象类型将仅接受其定义中提到的特定属性,而非精确或"开放"类型将接受额外的属性。 在 TypeScript 中,类型通常被视为开放且不精确。 这对于子类型和扩展接口非常有用:
interface Foo {
a: string
}
interface Bar extends Foo {
b: number
}
const bar: Bar = {a: "hey", b: 123};
const foo: Foo = bar; // okay
如果Foo
是精确的,那么Bar
就不是Foo
的有效扩展,bar
也不是Foo
的有效实例,并且几乎整个接口/类子类型/扩展/继承功能都会被破坏。
但是发现这种开放类型并没有捕获常见的错误类,人们会拼错可选属性的键。 如果属性是可选的,则可以将其省略,如果对象类型是打开的,则拼写错误的键只是一些额外的属性。 为了解决这个问题,该语言还进行了多余的财产检查,在非常有限的情况下,某些类型被视为精确。
具体来说,仅当您尝试在需要具体对象类型的位置使用全新的("新鲜")对象文本时,才会发生这种情况。 因此,如您所见,以下内容将是一个错误:
const excessError: Foo = { a: "hey", b: 123 }; // error!
// Object literal may only specify known properties, and 'b' does not exist in type 'Foo'.
如果在没有预期类型的地方使用对象文本,则会接受它:
const noTypeExpected = { a: "hey", b: 123 }; // no error
如果您重用不再"新鲜"的现有对象文本类型,它将被接受:
const notBrandNew: Foo = noTypeExpected; // no error
如果您使用通过泛型函数传递对象文字,则返回的类型将不再被视为"新鲜"类型:
const identity = <T>(x: T) => x;
const alsoNotBrandNew: Foo = identity({ a: "hey", b: 123 }); // no error
所以现在让我们看看承诺问题:
const promiseFoo: Promise<Foo> = Promise.resolve({ a: "hey", b: 123 }); // okay
这是有效的Promise.resolve(value)
因为它是一个具有以下签名的泛型函数:
interface PromiseConstructor {
resolve<T>(value: T | PromiseLike<T>): Promise<T>;
}
类型参数T
是从value
的类型推断出来的,{a: string, b: number}
。所以返回类型是Promise<{a: string, b: number}>
. 这可以分配给Promise<{a: string}>
(因为Promise
在其类型参数中是协变的,除非提示,否则我不会在这里讨论),因为该{a: string, b: number}
类型不再被视为新的对象文字类型。
那么,我们如何才能从Promise.resolve()
中得到"精确"的行为呢? 我能想到的最简单的方法是手动将泛型类型参数指定为Foo
,而不是从value
的类型推断出来:
const promiseExact = Promise.resolve<Foo>({ a: "hey", b: 123 }); // error!
// Object literal may only specify known properties,
// and 'b' does not exist in type 'Foo | PromiseLike<Foo>'.
现在发生错误是因为Promise.resolve<Foo>(value)
期望value
是一个Foo | PromiseLike<Foo>
,并且新对象文字被仔细检查,就好像它是精确的类型一样。
好的,希望有帮助;祝你好运!
链接到代码
似乎TypeScript将允许你写这个,但是,如果你写
testPromise.then(value => value.what)
然后,编译器将在此步骤中抱怨。