字符串与字符串文字不兼容

时间:2018-08-23 18:29:11

标签: javascript flowtype

此代码段中出现流错误

type MyType = 'aa' | 'bb'

const str = 'a'
const test1: MyType = `a${str}` // ERROR
const test2: MyType = 'a' + str // ERROR

错误

const test1: MyType = `a${str}` // ERROR
                         ^ Cannot assign template string to `test1` because: Either string [1] is incompatible with string literal `aa` [2]. Or string [1] is incompatible with string literal `bb` [3].
References:
6: const test1: MyType = `a${str}`  // ERROR
                         ^ [1]
3: type MyType = 'aa' | 'bb'
                 ^ [2]
3: type MyType = 'aa' | 'bb'
                        ^ [3]

链接:https://flow.org/try

有人知道为什么流程不支持这一点吗?还是有更好的方法编写此代码以使流程愉快?谢谢!

2 个答案:

答案 0 :(得分:2)

Flow是Javascript的静态类型检查器。这意味着流程仅以静态方式分析源代码。

在您的示例中,{strong}运行时的变量test1test2都等于aa,这等于{ {1}}。

不幸的是,这是运行时的结果。流仅检查静态规则。据我所知,Flow永远不会执行它检查的代码(即使代码像您的示例中那样琐碎)。

答案 1 :(得分:-1)

归因于wchargin

简短的回答:不要写

长答案:

以下是我想要此功能的原因:

// =====================
// Icon component
// =====================
// ICONS contains all the svg icons in the app
// I use prefix like FRUIT_ to differentiate the categories
const ICONS = {
  FRUIT_APPLE: <svg>...</svg>,
  FRUIT_ORANGE: <svg>...</svg>,
  VEGE_BROCCOLI: <svg>...</svg>,
  VEGE_TOMATO: <svg>...</svg>,
  ...
}

const Props = {
  type: $Keys<typeof ICONS>
}

const Icon = ({ type }: Props): Element<*> => (
  <i className={`Icon Icon--{type}`} />  
)

// =====================
// FruitCard component
// =====================
type Props = {
  fruitType: 'APPLE' | 'ORANGE',
  foo: string,
  ...
}

const FruitCard = (props: Props) => (
  <div>
     <div>{props.foo}</div>
     {/* Flow ERROR below */}
     <Icon type={`FRUIT_${props.fruitType}`} />
  </div>
) 

解决方案1:使用对象将fruitType转换为图标类型 这是我正在使用的解决方案

// =====================
// FruitCard component
// =====================
type Props = {
  fruitType: 'APPLE' | 'ORANGE',
  foo: string,
  ...
}

// Use object to convert fruitType to icon type
const FRUIT_TYPE_TO_ICON_TYPE = {
  APPLE: 'FRUIT_APPLE',
  ORANGE: 'FRUIT_ORANGE',
}

const FruitCard = (props: Props) => (
  <div>
     <div>{props.foo}</div>
     {/* This works in flow */}
     <Icon type={FRUIT_TYPE_TO_ICON_TYPE[props.fruitType]} />
  </div>
) 

解决方案2:使用$ ObjMap,将层次结构嵌入类型系统 这归因于wchargin。我认为这是一个更好的解决方案,因为它不需要对象映射。

import React, {type Element} from "react";

// Type definitions. (There are other ways to structure these; this is
// relatively simple and works fine.)
type IconCategories = {
  FRUIT: FruitTypes,
  VEGE: VegeTypes,
};
type FruitTypes = {
  APPLE: "APPLE",
  ORANGE: "ORANGE",
};
type VegeTypes = {
  BROCCOLI: "BROCCOLI",
  TOMATO: "TOMATO",
};

// ICONS contains all the SVG icons in the app.
// Each category has its own nested object.
// This will fail to typecheck if you forget to include a category, or
// include an extra category, or forget to include a fruit/vegetable, or
// include an extra fruit/vegetable, or if any of the leaves is not an
// <svg /> element.
const ICONS: $Exact<$ObjMap<IconCategories, <T>(T) =>
  $Exact<$ObjMap<T, <U>(U) => Element<"svg">>>
>> = {
  FRUIT: {
    APPLE: <svg />,
    ORANGE: <svg />,
  },
  VEGE: {
    BROCCOLI: <svg />,
    TOMATO: <svg />,
  },
};

// Icon component
// Example usage: <Icon category="FRUIT" type="APPLE" />.
const Icon = <T: $Keys<IconCategories>>(props: {
  category: T,
  type: $Keys<$ElementType<IconCategories, T>>,
}) => (
  <i className={`Icon Icon--${props.category}_${props.type}`} />
);

// The following typecheck (which is good):
<Icon category="FRUIT" type="APPLE" />;
<Icon category="VEGE" type="BROCCOLI" />;

// The following do not typecheck (which is good):
/*
<Icon category="FRUIT" type="BROCCOLI" />;
<Icon category="VEGE" type="APPLE" />;
<Icon category="NOT_A_CATEGORY" type="WAT" />;
<Icon category="FRUIT" type="NOT_A_FRUIT" />;
*/

// FruitCard component
type Props = {
  fruitType: "APPLE" | "ORANGE",  // or: `fruitType: $Keys<FruitTypes>`
  foo: string,
};

const FruitCard = (props: Props) => (
  <div>
    <div>{props.foo}</div>
    {/* This typechecks, correctly */}
    <Icon category="FRUIT" type={props.fruitType} />
  </div>
);

这里是关于github的更深入的讨论: https://github.com/facebook/flow/issues/6789