首页 > 解决方案 > 如果值在打字稿数组中,则分配新的字符串值

问题描述

如果不确定新值是否存在于有效字符串类型的数组中,如何为 Typescript 中的类型化字符串分配新值?例如

const fruits = ['apple', 'banana', 'orange'] as const;
type Fruit = typeof fruits[number];

export default function () {
  let selectedFruit: Fruit = 'apple';

  const url = new URL(window.location.href);
  const fruitParam = url.searchParams.get('fruit'); // type is string | null

  if (fruits.some((fruit) => fruitParam === fruit)) {
    selectedFruit = fruitParam; // Typescript error: Type 'string | null' is not assignable to type '"apple" | "banana" | "orange"'
  }

  return selectedFruit;
}

检查不应该fruits.some((fruit) => fruitParam === fruit))确保fruitParam确实是有效的水果类型吗?TS 编译器是否无法从该检查中推断?我也试过fruits.includes(fruit)和其他人没有任何运气。当然,明确列出类型fruitParam === 'apple' || fruitParam === 'banana' || fruitParam === 'orange' 确实有效,但并不理想。

标签: javascripttypescripttypes

解决方案


您需要处理类型兼容性。 selectedFruit可以是'apple', 'banana', 'orange' randomFruit你的情况之一,我只是一个字符串

所以,联合类型不能被扩展string string类型可以被扩展'apple', 'banana', 'orange'

因此,如果你写:

  let randomFruit = getRandomFruit();

  if (fruits.some((fruit) => randomFruit === fruit)) {
    randomFruit = selectedFruit // no error
    selectedFruit = randomFruit; // Typescript error: Type 'string' is not assignable to type '"apple" | "banana" | "orange"'
  }

它会起作用的。

所以,让我们回到你的问题。

为了更清楚,让我们as const添加basket

const basket = ['apple', 'banana', 'orange', 'lychee', 'pear', 'grapefruit'] as const;

现在,您有类似但更容易理解的错误消息:

Type '"apple" | "banana" | "orange" | "lychee" | "pear" | "grapefruit"' is not assignable to type '"apple" | "banana" | "orange"'

为了让它工作,你应该在fruits数组中定义所有可能的水果。你的篮子应该只允许fruits阵列中存在的水果 - 对我来说它确实有意义。

例子:

const fruits = ['apple', 'banana', 'orange', 'lychee', 'pear', 'grapefruit'] as const;
type Fruit = typeof fruits[number];

const basket = ['apple', 'banana', 'orange'] as const;

const getRandomFruit = () => basket[Math.floor(Math.random() * basket.length)];

export default function () {
  let selectedFruit: Fruit = 'apple';

  const randomFruit = getRandomFruit();

  if (fruits.some((fruit) => randomFruit === fruit)) {
    selectedFruit = randomFruit; // no error
  }

  return selectedFruit;
}

更新

在这里,您有一个带有 typeguard 的解决方案:

const fruits = ['apple', 'banana', 'orange'] as const;
type Fruit = typeof fruits[number];

/**
 * You should yo use typeguard instead of simple condition
 */
const isAllowedFruit = (fruit: string | null): fruit is Fruit => typeof fruit === 'string' ? fruits.includes(fruit as Fruit) : false

export default function () {
        let selectedFruit: Fruit = 'apple';

        const url = new URL(window.location.href);
        const fruitParam = url.searchParams.get('fruit'); // type is string | null

        if (isAllowedFruit(fruitParam)) {
                selectedFruit = fruitParam; // ok
        }

        return selectedFruit;
}

在这里您可以阅读有关类型保护的更多信息


推荐阅读