TypeScript 仅在输入为 undefined 时返回 unknown 的泛型

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

Typescript returns unknown for generic only on undefined input

问题

我正在尝试编写一个通用的环境字段获取函数目前有以下代码

```js
export interface Config {
  readonly PORT: number;
  readonly DATABASE_URL: string;
  // ... other fields
}
const config: Config = Object.freeze({
  ENVIRONMENT,
  PROJECT_NAME,
  PORT: parseInt(getEnvVariable('PORT', '9000'), 10),
  DATABASE_URL: getEnvVariable('DATABASE_URL'),
  AWS_REGION,
});

function getEnvVariable<T>(name: string, defaultValue?: T): T | string {
  const val = process.env[name];

  if (val) {
    return val;
  }

  if (defaultValue) {
    return defaultValue;
  }

  throw new Error(`Missing environment variable: ${name}`);
}

我目前遇到的错误是:

Type 'Readonly<{ ENVIRONMENT: string; PROJECT_NAME: string; PORT: number; DATABASE_URL: unknown; AWS_REGION: string; }>' is not assignable to type 'Config'.
  Types of property 'DATABASE_URL' are incompatible.
    Type 'unknown' is not assignable to type 'string'.

出现这个错误的原因是,如果我的 defaultValue 输入为 undefined,它会导致这个错误,即使我进行了真值检查。

如何在不使用 '' 作为 defaultValue 的情况下解决这个问题?


<details>
<summary>英文:</summary>

I&#39;m trying to write a generic env field getter function and currently have this:

```js
export interface Config {
  readonly PORT: number;
  readonly DATABASE_URL: string;
  // ... other fields
}
const config: Config = Object.freeze({
  ENVIRONMENT,
  PROJECT_NAME,
  PORT: parseInt(getEnvVariable(&#39;PORT&#39;, &#39;9000&#39;), 10),
  DATABASE_URL: getEnvVariable(&#39;DATABASE_URL&#39;),
  AWS_REGION,
});

function getEnvVariable&lt;T&gt;(name: string, defaultValue?: T): T | string {
  const val = process.env[name];

  if (val) {
    return val;
  }

  if (defaultValue) {
    return defaultValue;
  }

  throw new Error(`Missing environment variable: ${name}`);
}

and I'm currently getting the error:

Type &#39;Readonly&lt;{ ENVIRONMENT: string; PROJECT_NAME: string; PORT: number; DATABASE_URL: unknown; AWS_REGION: string; }&gt;&#39; is not assignable to type &#39;Config&#39;.
  Types of property &#39;DATABASE_URL&#39; are incompatible.
    Type &#39;unknown&#39; is not assignable to type &#39;string&#39;.

TypeScript 仅在输入为 undefined 时返回 unknown 的泛型

For some reason if my defaultValue input is undefined, it will give this error, even though I do a truthy check.

How would I fix this without using an &#39;&#39; as the defaultValue?

答案1

得分: 0

如果您不向 getEnvVariable 函数传递 defaultValue 参数,那么编译器将无法为泛型类型参数 T 推断出推断位置。因此,推断会失败,T 会回退到其约束,它隐式地是未知类型

如果您希望 T 在没有提供 defaultValue 时回退到其他值,您可以使用默认类型参数,如下所示:

function getEnvVariable<T = string>( 
  // 默认类型参数 ----> ^^^^^^^^ 
  name: string, defaultValue?: T
): T | string { /* 实现 */ }

然后,当未提供 defaultValue 时,您将获得所期望的行为:

const unsuppliedDefault = getEnvVariable("Y");
// const unsuppliedDefault: string

而当提供了 defaultValue 时,行为不会改变:

const suppliedDefault = getEnvVariable("X", Math.random());
// const suppliedDefault: string | number

Playground 上的代码链接

英文:

If you don't pass in a defaultValue argument to getEnvVariable, then the compiler has no inference site for the generic type parameter T. So inference fails, and T falls back to its constraint, which is implicitly the unknown type.

If you'd like T to fall back to something else, you can use a default type argument as shown here:

function getEnvVariable&lt;T = string&gt;( 
// default type arg ----&gt; ^^^^^^^^ 
  name: string, defaultValue?: T
): T | string { /* impl */ }

Then you'll get the desired behavior when defaultValue isn't supplied:

const unsuppliedDefault = getEnvVariable(&quot;Y&quot;);
// const unsuppliedDefault: string

without changing the behavior when it is:

const suppliedDefault = getEnvVariable(&quot;X&quot;, Math.random());
// const suppliedDefault: string | number

Playground link to code

huangapple
  • 本文由 发表于 2023年6月1日 22:57:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76383234.html
匿名

发表评论

匿名网友

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

确定