根据值是否存在推断属性类型

huangapple go评论79阅读模式
英文:

Infer prop type based on value being presnt

问题

这个示例的主要目标是在实体属性存在时,使 onClick 回调函数接收实体字符串,如果不存在实体属性,则不接收任何参数。

type SnakeOrCamelDomains = "light" | "switch" | "input_boolean" | "fan";
interface TestProps<S extends `${SnakeOrCamelDomains}.${string}`> {
  entity?: S;
  onClick: S extends `${SnakeOrCamelDomains}.${string}` ? (entity: string) => void : () => void;
}

function Test<S extends `${SnakeOrCamelDomains}.${string}`>({
  entity,
  onClick,
}: TestProps<S>) {
    return <button onClick={() => {
      if (typeof entity === 'string') {
        onClick(entity);
      } else {
        onClick();
      }
    }}>{entity}</button>;
}

这个示例在 TypeScript 中无法正常工作,因为 TypeScript 在此时无法了解 entity 或其值,因此期望你传递一个参数给 onClick。这种情况是否可能在 TypeScript 中实现呢?

英文:

I have a very simple example of what i'm trying to achieve, basically when the entity prop is present, i want the onClick callback to receive the entity string, if not it would receive nothing

type SnakeOrCamelDomains = &quot;light&quot; | &quot;switch&quot; | &quot;input_boolean&quot; | &quot;fan&quot;;
interface TestProps&lt;S extends `${SnakeOrCamelDomains}.${string}`&gt; {
  entity?: S;
  onClick: S extends `${SnakeOrCamelDomains}.${string}` ? (entity: string) =&gt; void : () =&gt; void;
}

function Test&lt;S extends `${SnakeOrCamelDomains}.${string}`&gt;({
  entity,
  onClick,
}: TestProps&lt;S&gt;) {
    return &lt;button onClick={() =&gt; {
      if (typeof entity === &#39;string&#39;) {
        onClick(entity);
      } else {
        onClick();
      }
    }}&gt;{entity}&lt;/button&gt;
}

This example above doesn't work with typescript, it's expecting me to pass an argument to onClick, naturually... as typescript doesn't know anything about entity or it's value at this point.

Is this possible with typescript?

答案1

得分: 1

错误的原因是类型 S${SnakeOrCamelDomains}.${string} 的子类型,因此 TypeScript 期望 S 始终是一个字符串。

即使 entity 是可选的并且可能为undefined,由于 S 始终扩展${SnakeOrCamelDomains}.${string},TypeScript 仍然推断 onClick 的类型为 (entity: string) => void

如果您希望 onClick 函数可以选择地接受一个实体作为参数,您可以将其类型更改为接受一个可选的字符串参数的函数:

interface TestProps<S extends `${SnakeOrCamelDomains}.${string}`> {
  entity?: S;
  onClick: (entity?: string) => void;
}
英文:

The reason you're having this error is because the type S is a subtype of ${SnakeOrCamelDomains}.${string}, and because of that, TypeScript expects S to always be a string.

Even though entity is optional and could be undefined, TypeScript still infers onClick as (entity: string) =&gt; void due to S always extending ${SnakeOrCamelDomains}.${string}.

If you want the onClick function to be optionally called with an entity, you can change its type to a function that takes an optional string argument:

interface TestProps&lt;S extends `${SnakeOrCamelDomains}.${string}`&gt; {
  entity?: S;
  onClick: (entity?: string) =&gt; void;
}

huangapple
  • 本文由 发表于 2023年7月11日 15:05:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76659434.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定