排除基元的 TypeScript 类型注释
TypeScript Type Annotation Excluding Primitives
问题:
有什么方法可以在 TypeScript 中编写允许任何对象文字但不允许内置类型 number
、string
、boolean
、Function
或Array
?
为什么?
我一直致力于为我在工作项目中使用的一些库改进 DefinitelyTyped 上的一些类型定义。我在许多 JS 库中注意到的一个常见模式是传递用于配置库或插件的 'options' 对象。在这些情况下,您经常会看到类似这样的类型定义:
declare module 'myModule' {
interface IMyModule {
(opts?: IOptions): NodeJS.ReadWriteStream;
}
interface IOptions {
callback?: Function;
readonly?: boolean;
}
}
这允许您像这样使用它:
var myModule = require('myModule');
myModule();
myModule({});
myModule({ callback: () => {} });
myModule({ readonly: false });
myModule({ callback: () => {}, readonly: false });
这些都是有效的用例。问题是这些类型定义还允许这些无效用例:
myModule('hello');
myModule(false);
myModule(42);
myModule(() => {});
myModule([]);
在许多情况下,上述调用会导致运行时错误,因为库 JS 代码可能会尝试在对象上设置默认值,或将选项传递给另一个库。虽然我已经尝试了很多东西,但我无法将参数限制为只接受对象而不接受任何其他无效情况。
似乎如果你有一个只有可选成员的接口(因为不需要任何一个选项),编译器会扩大可接受的类型以接受 any
。
您可以在此处查看此问题的 TypeScript Playground 演示:http://bit.ly/1Js7tLr
更新:一个不起作用的解决方案示例
interface IOptions {
[name: string]: any;
callback?: Function;
readonly?: boolean;
}
此尝试要求对象上存在索引运算符,这意味着它现在抱怨 number
s、string
s、boolean
s、Function
s 和 Array
s。但这会产生一个新问题:
var opts = {};
myModule(opts);
现在这应该是一个有效的场景却失败了。 (在 Playground 中查看:http://bit.ly/1MPbxfX)
要使接口具有合理的执行,它必须至少有一个强制成员。本质上,下面的接口不执行任何操作:
interface IOptions {
callback?: Function;
readonly?: boolean;
}
实际上相当于"evil interface":
interface IOptions {
}
所以你得到的是自动完成,但没有真正的类型检查。
您提出的解决方案是可行的方法...
interface IOptions {
[name: string]: any;
callback?: Function;
readonly?: boolean;
}
在大多数情况下,人们倾向于在函数调用中构建这些选项,但如果他们真的想在其他地方这样做,他们可以使用类型断言:
// If you must
var opts = <IOptions>{};
myModule(opts);
// More typical
myModule({});
// Although... if its empty
myModule();
免责声明。其中一小部分只是我的意见......但是空接口是你可以用 TypeScript 中的接口做的最糟糕的事情,而没有强制执行的是第二糟糕的事情。
您可以使用自己的基本接口避免重复...
interface Indexed {
[name: string]: any;
}
甚至...
interface Indexed<T> {
[name: string]: T;
}
然后在你所有的选项界面上使用它...
interface IOptions extends Indexed {
callback?: Function;
readonly?: boolean;
}
从 TypeScript 2.2 开始,现在有一个 object
类型几乎完全符合我上面描述的内容。
... you can assign anything to the object
type except for string
, boolean
, number
, symbol
, and, when using strictNullChecks
, null
and undefined
.
在这里查看官方公告:Announcing TypeScript 2.2
问题:
有什么方法可以在 TypeScript 中编写允许任何对象文字但不允许内置类型 number
、string
、boolean
、Function
或Array
?
为什么?
我一直致力于为我在工作项目中使用的一些库改进 DefinitelyTyped 上的一些类型定义。我在许多 JS 库中注意到的一个常见模式是传递用于配置库或插件的 'options' 对象。在这些情况下,您经常会看到类似这样的类型定义:
declare module 'myModule' {
interface IMyModule {
(opts?: IOptions): NodeJS.ReadWriteStream;
}
interface IOptions {
callback?: Function;
readonly?: boolean;
}
}
这允许您像这样使用它:
var myModule = require('myModule');
myModule();
myModule({});
myModule({ callback: () => {} });
myModule({ readonly: false });
myModule({ callback: () => {}, readonly: false });
这些都是有效的用例。问题是这些类型定义还允许这些无效用例:
myModule('hello');
myModule(false);
myModule(42);
myModule(() => {});
myModule([]);
在许多情况下,上述调用会导致运行时错误,因为库 JS 代码可能会尝试在对象上设置默认值,或将选项传递给另一个库。虽然我已经尝试了很多东西,但我无法将参数限制为只接受对象而不接受任何其他无效情况。
似乎如果你有一个只有可选成员的接口(因为不需要任何一个选项),编译器会扩大可接受的类型以接受 any
。
您可以在此处查看此问题的 TypeScript Playground 演示:http://bit.ly/1Js7tLr
更新:一个不起作用的解决方案示例
interface IOptions {
[name: string]: any;
callback?: Function;
readonly?: boolean;
}
此尝试要求对象上存在索引运算符,这意味着它现在抱怨 number
s、string
s、boolean
s、Function
s 和 Array
s。但这会产生一个新问题:
var opts = {};
myModule(opts);
现在这应该是一个有效的场景却失败了。 (在 Playground 中查看:http://bit.ly/1MPbxfX)
要使接口具有合理的执行,它必须至少有一个强制成员。本质上,下面的接口不执行任何操作:
interface IOptions {
callback?: Function;
readonly?: boolean;
}
实际上相当于"evil interface":
interface IOptions {
}
所以你得到的是自动完成,但没有真正的类型检查。
您提出的解决方案是可行的方法...
interface IOptions {
[name: string]: any;
callback?: Function;
readonly?: boolean;
}
在大多数情况下,人们倾向于在函数调用中构建这些选项,但如果他们真的想在其他地方这样做,他们可以使用类型断言:
// If you must
var opts = <IOptions>{};
myModule(opts);
// More typical
myModule({});
// Although... if its empty
myModule();
免责声明。其中一小部分只是我的意见......但是空接口是你可以用 TypeScript 中的接口做的最糟糕的事情,而没有强制执行的是第二糟糕的事情。
您可以使用自己的基本接口避免重复...
interface Indexed {
[name: string]: any;
}
甚至...
interface Indexed<T> {
[name: string]: T;
}
然后在你所有的选项界面上使用它...
interface IOptions extends Indexed {
callback?: Function;
readonly?: boolean;
}
从 TypeScript 2.2 开始,现在有一个 object
类型几乎完全符合我上面描述的内容。
... you can assign anything to the
object
type except forstring
,boolean
,number
,symbol
, and, when usingstrictNullChecks
,null
andundefined
.
在这里查看官方公告:Announcing TypeScript 2.2