我想创建一个函数对象,其中也有它持有一些属性。 例如在JavaScript中我会做:
var f = function() { }
f.someValue = 3;
现在,在我的打字原稿可以将此描述为的类型:
var f: { (): any; someValue: number; };
但是我不能真正建立它,而无需转换。 如:
var f: { (): any; someValue: number; } =
<{ (): any; someValue: number; }>(
function() { }
);
f.someValue = 3;
你将如何建立这个没有投?
Answer 1:
因此,如果要求是简单地构建和功能分配到“f”不进行强制转换,这里是一个可能的解决方案:
var f: { (): any; someValue: number; };
f = (() => {
var _f : any = function () { };
_f.someValue = 3;
return _f;
})();
本质上,它采用的是自执行函数文本“构造”的对象分配完成之前,将匹配的签名。 唯一古怪的是,该功能的内部声明必须是类型“任意”的,否则编译器的呼喊,你分配给它没有在对象上还存在一个属性。
编辑:简化的代码位。
Answer 2:
更新:这个答案是在早期版本的打字稿的最佳解决方案,但也有新的版本(见其他答案)提供更好的选择。
接受答案的工作,并可能在某些情况下是必需的,但必须提供建立对象没有类型安全的缺点。 这种技术将至少抛出一个类型的错误,如果你尝试添加一个未定义的属性。
interface F { (): any; someValue: number; }
var f = <F>function () { }
f.someValue = 3
// type error
f.notDeclard = 3
Answer 3:
现在这是很容易实现(打字稿2.X)与Object.assign(target, source)
例:
这里的神奇的是, Object.assign<T, U>(t: T, u: U)
被键入返回的交点 T & U
。
强制执行,这解析为一个已知的界面也是简单。 例如:
interface Foo {
(a: number, b: string): string[];
foo: string;
}
let method: Foo = Object.assign(
(a: number, b: string) => { return a * a; },
{ foo: 10 }
);
这是由于不兼容的输入错误:
错误:FOO:数不分配给foo:字符串
错误:号码不能分配给串[](返回类型)
警告:您可能需要填充工具 ,如果针对旧版本浏览器Object.assign。
Answer 4:
打字稿是专门用来处理通过这个案例申报合并 :
你也可以是熟悉创建一个功能,然后通过添加属性到功能进一步延伸的功能的JavaScript的实践。 打字稿使用声明合并来建立这样定义的类型安全的方式。
宣言合并让我们说什么是两种功能:和一个命名空间(内部模块):
function f() { }
namespace f {
export var someValue = 3;
}
这保留了打字,让我们写两个f()
和f.someValue
。 当编写一个.d.ts
文件现有的JavaScript代码,使用declare
:
declare function f(): void;
declare namespace f {
export var someValue: number;
}
添加属性到功能往往是在一个打字原稿混淆或意想不到的图案,所以尽量避免它,但使用或转化的年龄较大的JS代码时,它是必要的。 这是唯一的时候,它是适当的内部模块(命名空间)与外部混合之一。
Answer 5:
作为快捷方式,则可以使用[“属性”]存取动态分配对象值:
var f = function() { }
f['someValue'] = 3;
这种绕过类型检查。 但是,因为你要有意访问属性相同的方式,它是非常安全:
var val = f.someValue; // This won't work
var val = f['someValue']; // Yeah, I meant to do that
但是,如果你真的想要的类型检查的属性值,这是不行的。
Answer 6:
更新的答案:因为通过添加交集类型&
,就可以“合并”两种推断类型的飞行。
下面是一些读对象的属性一般帮手from
在物体上,并将它们复制onto
。 它返回相同的对象onto
,但用新的类型,其包括两组特性,所以正确地描述的运行时行为:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
这种低级别的帮手也仍然执行一个类型的断言,但它是类型安全的设计。 有了这个帮手的地方,我们有一个运营商,我们可以使用全型安全解决OP的问题:
interface Foo {
(message: string): void;
bar(count: number): void;
}
const foo: Foo = merge(
(message: string) => console.log(`message is ${message}`), {
bar(count: number) {
console.log(`bar was passed ${count}`)
}
}
);
点击这里尝试一下了打字稿游乐场 。 请注意,我们已经限制foo
为类型Foo
,所以结果merge
已经是一个完整的Foo
。 所以,如果你重新命名bar
到bad
,那么你得到一个类型的错误。
NB还有这里一个类型孔,但是。 打字稿不提供一种方式来约束一个类型参数为“不是一个函数”。 所以,你可能会感到困惑,并通过你的函数作为第二个参数来merge
,并且是行不通的。 所以,直到可以声明,我们必须抓住它在运行时:
function merge<T1, T2>(onto: T1, from: T2): T1 & T2 {
if (typeof from !== "object" || from instanceof Array) {
throw new Error("merge: 'from' must be an ordinary object");
}
Object.keys(from).forEach(key => onto[key] = from[key]);
return onto as T1 & T2;
}
Answer 7:
我不能说这是很简单,但它绝对有可能:
interface Optional {
<T>(value?: T): OptionalMonad<T>;
empty(): OptionalMonad<any>;
}
const Optional = (<T>(value?: T) => OptionalCreator(value)) as Optional;
Optional.empty = () => OptionalCreator();
如果你有自信,这是从我的使用的打字稿/ JavaScript版本要旨Optional
Answer 8:
这偏离了强类型,但你可以做
var f: any = function() { }
f.someValue = 3;
如果你想避开压迫感强类型像我是当我发现这个问题。 可悲的是,这是对案件的打字稿未能完全有效的JavaScript,所以你必须告诉打字稿打退堂鼓了。
“你JavaScript是非常有效的打字稿”评估为假。 (注:使用0.95)
Answer 9:
老问题,但首先是3.1打字稿的版本,你可以简单地做属性赋值,你会以纯JS,只要您使用函数声明或者const
为您的变量关键字:
function f () {}
f.someValue = 3; // fine
const g = function () {};
g.someValue = 3; // also fine
var h = function () {};
h.someValue = 3; // Error: "Property 'someValue' does not exist on type '() => void'"
参考和在线例子 。
文章来源: Build a function object with properties in TypeScript