英文:
Is there a way to add correct type annotations for this TypeScript code with an inline function class?
问题
可以添加哪些类型注解来通知 TypeScript 此代码是正确的?
是的,我确实需要内联函数类。此代码已从我的实际问题简化为此简化版本。
let x: number = 10;
const obj: { constructor(): any } = new (function() {
if (--x) return this.constructor();
return {};
});
'this' 隐式具有类型 'any',因为它没有类型注解.ts(2683)
'new' 表达式的目标缺乏构造函数签名,隐式具有类型 'any'。ts(7009)
我尝试完全注释所有内容,但这并不能解决问题。以下是示例:
type myType = { constructor(): myType };
let x: number = 10;
const obj: myType = new (function(): myType {
if (--x) return (this as myType).constructor();
return {} as myType;
});
'new' 表达式的目标缺乏构造函数签名,隐式具有类型 'any'。ts(7009)
我是否遗漏了 TypeScript 文档中的某些内容?似乎没有任何通用的构造函数类型,并且构造函数类型似乎并不适用于构造函数。
英文:
What type annotations can I add to inform TypeScript that this code is correct?
Yes I do need that inline function class. This code has been reduced from my actual problem to this simplified version.
let x = 10;
const obj = new (function() {
if(--x) return this.constructor();
return {};
});
'this' implicitly has type 'any' because it does not have a type annotation.ts(2683)
'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009)
I tried totally annotating everything and that doesn't fix it. Here is what that looks like:
type myType = { constructor(): myType };
let x: number = 10;
const obj: myType = new (function(): myType {
if(--x) return (this as myType).constructor();
return {} as myType;
});
'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.ts(7009)
Is there something in the TypeScript docs I'm missing? There don't seem to be any Constructor types that are generic and the Constructor types don't really appear to be for constructors.
答案1
得分: 1
如果你想说一个类型是可"newable"的,或者是new
操作符的有效目标,你应该使用一个构造函数签名。构造函数签名可以写成{ new (⋯): ⋯}
,就像一个调用签名,或者写成new (⋯) => ⋯
,就像一个箭头函数表达式。
以下是一种编写代码以使其编译的方法:
let x = 10;
type MyType = { new(): {} };
const obj = new ((function (this: {}) {
console.log(x);
if (--x) return this.constructor();
return {};
}) as any as MyType);
这里我们将 MyType
定义为 { new(): {} }
,一个没有构造函数参数并产生类型为 {}
的构造函数签名。
然后我们通过 (⋯) as any as MyType
断言了匿名函数表达式的类型为 MyType
。请注意,(⋯) as MyType
会失败,因为TypeScript 不认为可调用类型和可实例化类型之间的关系足够密切以允许它们之间的直接断言。(在现代 JavaScript 中,大多数类构造函数如果你尝试在没有 new
的情况下调用它们,它们会报错,而箭头函数如果你尝试用 new
调用它们而不是调用它们,它们会报错,所以 TypeScript 故意将它们分开。)你需要一个中间的东西,被认为与两者都相关;我选择了 any
类型,但你也可以选择其他的,比如 Function
。
另外,我给了匿名函数一个类型为 {}
的 this
参数,这样编译器在函数体内处理 this
时会很高兴。
总之,现在没有错误了,obj
的值被推断为类型 {}
。显然在你实际的用例中,你需要找出符合你需求的类型,但假设无论那些是,它们都会涉及至少一个构造函数签名。
英文:
If you want to say that a type is "newable", or a valid target for the new
operator, you should use a construct signature. A construct signature can be written either as { new (⋯): ⋯}
like a call signature or as new (⋯) => ⋯
like an arrow function expression.
Here's one way to write your code so it compiles:
let x = 10;
type MyType = { new(): {} };
const obj = new ((function (this: {}) {
console.log(x);
if (--x) return this.constructor();
return {};
}) as any as MyType);
Here we've defined MyType
as { new(): {} }
, a construct signature that takes no constructor arguments and produces a value of type {}
.
Then we've asserted that the anonymous function expression is of type MyType
via (⋯) as any as MyType
. Note that (⋯) as MyType
fails because TypeScript doesn't see callable types and newable types as related enough to allow direct assertions between them. (In modern JavaScript, most class constructors will complain if you try to call them without new
, and arrow functions complain if you try to new
them instead of calling them, so TypeScript separates these on purpose.) You need something intermediate that is seen as related to both; I chose the any
type but you could something else, like Function
for example.
Also I gave the anonymous function a this
parameter of type {}
, so that the compiler would be happy manipulating this
inside the function body.
Anyway, now there is no error, and the value of obj
is inferred as being of type {}
. Obviously in your actual use case you'll need to figure out the typings that meet your needs, but presumably whatever those are they will involve at least one construct signature.
答案2
得分: 0
将其从(...a: A) => B
类型映射到new (...a: A) => B
的通用映射:
function fakeNewable<F extends (...a: any) => any>(
fn: F,
): (new (...a: Parameters<F>) => ReturnType<F>) /* ` & F` if you also need other props */ {
return fn as any
}
function foo() {
return Math.random() > 0.5 ? 'foo' : { foo: 'bar' };
}
let v = new (fakeNewable(foo))
// ^?
// let v: string | { foo: string; }
(请记住,如果在new
调用中返回undefined
,您将得到构造的对象)
英文:
Make a generic to map it from (...a: A) => B
type to new (...a: A) => B
function fakeNewable<F extends (...a: any) => any>(
fn: F,
): (new (...a: Parameters<F>) => ReturnType<F>) /* ` & F` if you also need other props */ {
return fn as any
}
function foo() {
return Math.random() > 0.5 ? 'foo' : { foo: 'bar' };
}
let v = new (fakeNewable(foo))
// ^?
// let v: string | { foo: string; }
(remember, that if you return undefined
inside new
call, you'll get the constructed object)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论