【问题标题】:How can I map some parameters to be optional?如何将某些参数映射为可选?
【发布时间】:2018-06-13 08:02:22
【问题描述】:

上下文:

我正在尝试编写一个函数,该函数将允许该函数的用户使用 no typescript type assertions(只是简单的旧 javascript 语法)定义某种类型。基本上,我正在尝试编写类似 React 的 PropTypes 的东西,但我想将使用这些“PropTypes”定义的类型映射到可以使用 typescript 强制执行的类型。

也许通过查看代码更容易理解我想要做什么。 defineFunction 下面是一个函数,它返回一个函数,该函数接受由“PropTypes”`定义的对象。

interface PropType<T> { isOptional: PropType<T | undefined> }
type V<Props> = {[K in keyof Props]: PropType<Props[K]>};
interface PropTypes {
  string: PropType<string>,
  number: PropType<number>,
  bool: PropType<boolean>,
  shape: <R>(definer: (types: PropTypes) => V<R>) => PropType<R>
}

// the only purpose of this function is to capture the type and map it appropriately
// it does do anything else
function defineFunction<Props, R>(props: (types: PropTypes) => V<Props>, func: (prop: Props) => R) {
  return func;
}

// define a function
const myFunction = defineFunction(
  // this is the interface definition that will be mapped
  // to the actual required props of the function
  types => ({
    stringParam: types.string,
    optionalNumberParam: types.number.isOptional,
    objectParam: types.shape(types => ({
      nestedParam: types.string,
    }))
  }),
  // this is the function definition. the type of `props`
  // is the result of the mapped type above
  props => {
    props.objectParam.nestedParam
    return props.stringParam;
  }
);

// use function
myFunction({
  stringParam: '',
  optionalNumberParam: 0,
  objectParam: {
    nestedParam: ''
  }
});

这是通过将鼠标悬停在 VS Code 中的类型上找到的 myFunction 的结果类型:

const myFunction: (prop: {
    stringParam: string;
    optionalNumberParam: number | undefined;
    objectParam: {
        nestedParam: string;
    };
}) => string

问题:

上面的代码有一个问题——optionalNumberParam 被正确定义为 number | undefined 但它实际上不是可选的!

如果我省略了optionalNumberParam,打字稿编译器会骂我。

有没有断言一个类型是可选的,而不仅仅是T | undefined


回复cale_b的评论:

只是一个想法 - 你尝试过 optionalNumberParam 吗?:types.number.isOptional

是的,这是无效的语法:

澄清一下,这个defineFunction 应该让用户使用no typescript type assertions定义一个类型——而不是所有东西都应该使用映射类型来推断。 ? 只是打字稿。我正在尝试编写此函数,以便 - 从理论上讲 - javascript 用户可以定义 proptypes 并且仍然让 typescript 编译器强制执行这些 proptypes。

【问题讨论】:

  • @cale_b 查看更新后的答案。在那里添加了一个屏幕截图,因为我无法在 cmets 中添加一个
  • 很好的说明。谢谢,祝你好运!在这一点上超出我的深度...... :)
  • 我没有给你很好的解决方案;您可能会发现需要指定两种对象字面量:一种用于必需参数,另一种用于可选参数,其结果是两种映射类型的交集(一种带问号,一种不带问号)。
  • @jcalz 对于解决方法来说这不是一个坏主意。我开始认为我所要求的还不可能。我将在 typescript github 上打开一个问题,一旦完成提案,我将链接到它
  • @jcalz 这是我刚刚提交的提案:github.com/Microsoft/TypeScript/issues/20984

标签: javascript typescript mapped-types


【解决方案1】:

所以,我能做的最接近的解决方法是我提到的双对象文字解决方案:

interface PropType<T> { type: T }

首先我删除了isOptional,因为它对你没有好处,其次我添加了一个带有T的属性,因为TypeScript不一定能区分PropType&lt;T&gt;PropType&lt;U&gt;如果TU 不同,除非它们在结构上不同。不过,我认为您不需要使用 type 属性。

然后是一些我没碰过的东西:

type V<Props> = {[K in keyof Props]: PropType<Props[K]>};
interface PropTypes {
  string: PropType<string>,
  number: PropType<number>,
  bool: PropType<boolean>,
  shape: <R>(definer: (types: PropTypes) => V<R>) => PropType<R>
}
function defineFunction<Props, R>(props: (types: PropTypes) => V<Props>, func: (prop: Props) => R) {
  return func;
}

现在,我正在创建函数withPartial,它接受RO 类型的两个参数并返回R &amp; Partial&lt;O&gt; 类型的值。

function withPartial<R, O>(required: R, optional: O): R & Partial<O> {
  return Object.assign({}, required, optional);
}

让我们试试吧:

const myFunction = defineFunction(
  types => withPartial(
    {
      stringParam: types.string,
      objectParam: types.shape(types => ({
        nestedParam: types.string,
      }))
    },
    {
      optionalNumberParam: types.number
    }
  ),
  props => {
    props.objectParam.nestedParam
    return props.stringParam;
  }
);

请注意我如何将原始对象字面量分成两部分:一个具有必需属性,另一个具有可选属性,然后使用withPartial 函数重新组合它们。还要注意withPartial() 的用户不需要使用任何特定于 TypeScript 的符号,我认为这是您的要求之一。

检查myFunction 的类型会给你:

const myFunction: (
  prop: {
    stringParam: string;
    objectParam: {
      nestedParam: string;
    };
    optionalNumberParam?: number;
  }
) => string

这就是你想要的。观察:

// use function
myFunction({
  stringParam: '',
  //optionalNumberParam: 0,  // no error
  objectParam: {
    nestedParam: ''
  }
});

希望有所帮助;祝你好运!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-21
    • 2013-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-06
    相关资源
    最近更新 更多