最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - TypeScript `unknown` doesn't allow non-unknown types in function parameters - Stack Overflow

programmeradmin1浏览0评论

Why doesn't this work?

const x: unknown[] = ['x', 32, true]; // OK
const y: (...args: unknown[]) => unknown = (xx: number) => {}; // ERROR

// Type '(xx: number) => void' is not assignable to type '(...args: unknown[]) => unknown'.
//  Types of parameters 'xx' and 'args' are inpatible.
//    Type 'unknown' is not assignable to type 'number'. ts(2322)

My goal is to make sure that y is any runnable function. I was trying not to use any. Hope to improve my understanding of how unknown works in this case.

Why doesn't this work?

const x: unknown[] = ['x', 32, true]; // OK
const y: (...args: unknown[]) => unknown = (xx: number) => {}; // ERROR

// Type '(xx: number) => void' is not assignable to type '(...args: unknown[]) => unknown'.
//  Types of parameters 'xx' and 'args' are inpatible.
//    Type 'unknown' is not assignable to type 'number'. ts(2322)

My goal is to make sure that y is any runnable function. I was trying not to use any. Hope to improve my understanding of how unknown works in this case.

Share edited Dec 30, 2022 at 16:38 Sam Chen asked Dec 30, 2022 at 15:59 Sam ChenSam Chen 1571 silver badge10 bronze badges 7
  • 1 What you're doing isn't safe. Presumably you would want const y: (...args: unknown[]) => unknown = (xx: number) => xx.toFixed() to pile, but then y("x", 32, true) would be accepted by the piler and subsequently blow up at runtime. What do you plan to do with y once it exists? That will determine how it should be declared. – jcalz Commented Dec 30, 2022 at 16:09
  • I'm trying to make a definition for a module within the dependency injection library didi which isn't very type-safe either. Module declarations are one of the following: ['type', FunctionConstructor], ['factory', FactoryFunction], ['value', unknown]. – Sam Chen Commented Dec 30, 2022 at 16:16
  • I used the example above to simplify the reason for the error. y should actually return something specific. I left it empty for simplicity. But there's no way I know the function parameters of every factory function I may want to use for injection later on. I use unknown since didi doesn't have the type bindings to give me each factory function's return type when I inject anyway, so I'm essentially casting the injected value's type at the destination. – Sam Chen Commented Dec 30, 2022 at 16:18
  • There is a (mostly) safe top type for functions; it's (...args: never) => unknown. It's the unknown of functions. But as such, it's almost useless to have a value annotated of that type; the piler won't let you call it. This is the general tradeoff with types; the less you specify about a type, the easier it is to produce values of that type and the harder it is to consume values of that type. I wish you'd edit to show a minimal reproducible example of someone using y, since that drives the answer. Perhaps you don't want to annotate at all and instead use satisfies like this? – jcalz Commented Dec 30, 2022 at 16:27
  • 1 If you're not calling the functions in TypeScript then I guess I don't need a minimal reproducible example. I'll write up an answer. – jcalz Commented Dec 30, 2022 at 16:39
 |  Show 2 more ments

2 Answers 2

Reset to default 7

Function types are contravariant in their parameter types; see Difference between Variance, Covariance, Contravariance and Bivariance in TypeScript for more details. Contravariance means the direction of assignability flips; if T is assignable to U, then (...u: U) => void is assignable to (...t: T) => void and not vice versa. This is necessary for type safety. Picture the direction of data flow: if you want fruit then I can give you an apple, but if you want something that will eat all your fruit I can't give you something that eats only apples.


The function type (xx: number) => void is equivalent to (...args: [number]) => void, and you cannot assign that to (...args: unknown[]) => void. Yes, [number] is assignable to unknown[], but that's not the direction we care about. Your assignment is therefore unsafe. If this worked:

const y: (...args: unknown[]) => unknown =
    (xx: number) => xx.toFixed(); // should this be allowed?

Then you'd be able to call y() with any set of arguments you wanted without a piler error, but hit a runtime error:

y("x", 32, true); // no piler error
// 
发布评论

评论列表(0)

  1. 暂无评论