简体   繁体   English

Typescript 错误:扩展推断类型可防止 TS Linting 错误(提供了 Playground 示例)

[英]Typescript Bug: Extending An Inferred Type Prevents TS Linting Errors (Playground Example Provided)

I have a function called myStyles , which takes a single argument.我有一个名为myStyles的函数,它接受一个参数。 This argument is an object containing a baseStyles object and a styleVariants object.此参数是一个包含baseStyles对象和styleVariants对象的对象。 It simply returns the styleVariants object.它只是返回styleVariants对象。

function myStyles<StyleVariants extends StyleVariantsStructure>(params: {
  baseStyles: AllowedStyles;
  styleVariants: StyleVariants;
}): StyleVariants {
  return params.styleVariants;
}

It is called like so:它是这样调用的:

myStyles({
  baseStyles: {
    color: 'red',
    backgroundColor: 'red',
  },
  styleVariants: {
    color: {
      red: {
        color: 'red',
        backgroundColor: 'red',
      },
    },
  },
});

The baseStyles object has the type AllowedStyles , which determines which css properties and values we allow. baseStyles对象的类型为AllowedStyles ,它决定了我们允许使用哪些 css 属性和值。 This works perfectly and we get the correct TS errors if the CSS properties or values are misspelled when calling the myStyles function eg这很完美,如果在调用myStyles函数时 CSS 属性或值拼写错误,我们会得到正确的 TS 错误,例如

type AllowedStyles = {
  color?: 'red';
  backgroundColor?: 'red';
};

The styleVariants object has the type StyleVariantsStructure . styleVariants对象的类型为StyleVariantsStructure This essentially determines that it should accept one or many nested objects that contain the AllowedStyles eg这实质上决定了它应该接受一个或多个包含AllowedStyles嵌套对象,例如

type StyleVariantsStructure = {
  [k: string]: {
    [k: string]: AllowedStyles;
  };
};

In the myStyles function, we use type inference for the styleVariants param object.myStyles函数中,我们对styleVariants参数对象使用类型推断。 Meaning, we automatically get the exact type of the styleVariants passed in to the myStyles function.这意味着,我们会自动获取传递给myStyles函数的styleVariants的确切类型。 We then use the styleVariants type as the return type for the function.然后我们使用styleVariants类型作为函数的返回类型。 This is required for us, because we need to know the exact return type of myStyles .这对我们来说是必需的,因为我们需要知道myStyles的确切返回类型。 Here's our function again:这是我们的功能:

function myStyles<StyleVariants extends StyleVariantsStructure>(params: {
  baseStyles: AllowedStyles;
  styleVariants: StyleVariants;
}): StyleVariants {
  return params.styleVariants;
}

And here's an example of the type inference return type, taken from a Typescript playground I've used to demo this issue :这是类型推断返回类型的示例,取自我用来演示此问题Typescript 游乐场

在此处输入图片说明

The problem问题

As you can see, I need to both restrict things being passed in the styleVariants object, using the StyleVariantsStructure type eg we must only accept AllowedStyles .如您所见,我需要使用StyleVariantsStructure类型来限制在styleVariants对象中传递的styleVariants ,例如我们必须只接受AllowedStyles However, we also need to use the inferred type from styleVariants for the return type of the myStyles function.但是,我们还需要使用从styleVariants推断出的类型作为myStyles函数的返回类型。 I have attempted to solve this by using StyleVariants extends StyleVariantsStructure .我试图通过使用StyleVariants extends StyleVariantsStructure来解决这个StyleVariants extends StyleVariantsStructure This works somewhat, but some Typescript errors aren't highlighted in the styleVariants argument object when calling myStyles .这在一定程度上起作用,但是在调用myStyles时, styleVariants参数对象中未突出显示某些 Typescript 错误。

For example, if color is misspelled, we get no TS error:例如,如果color拼写错误,我们不会得到 TS 错误:

在此处输入图片说明

However, I do get type suggestions:但是,我确实得到了类型建议:

在此处输入图片说明

And, I do get errors if the value is misspelled:而且,如果值拼写错误,我确实会收到错误消息:

在此处输入图片说明

Essentially, to me, it seems like I need to find an alternate way to use type inference for the styleVariants object, whilst also restricting it using the StyleVariantsStructure type.本质上,对我来说,似乎我需要找到一种替代方法来对styleVariants对象使用类型推断,同时还使用StyleVariantsStructure类型对其进行限制。 Any help on this would be much appreciated.对此的任何帮助将不胜感激。

Minimal demo of the issue in Typescript playground Typescript 操场中问题的最小演示

Strictly speaking, this looks correct, but TS needs to be coaxed into checking it.严格来说,这看起来是正确的,但需要哄着 TS 去检查它。 For example, wrapping the call in the playground with console.log() generates the typechecking you want.例如,使用 console.log() 将调用包装在 Playground 中会生成您想要的类型检查。

TS is imperfect as a checker, so it can take some finagling for it to detect the "right" solution in highly complex situations - which this is! TS 作为检查器并不完美,因此在高度复杂的情况下它可能需要一些技巧才能检测到“正确”的解决方案 - 这就是!

The problem seems to be a limitation of Typescript more than anything else.问题似乎更像是 Typescript 的限制。 A workaround, which is a complete solution for us, that I found is the following:我发现的一种解决方法,对我们来说是一个完整的解决方案,如下所示:

function myStyles<StyleVariants>(params: {
  baseStyles: AllowedStyles;
  styleVariantKeys: StyleVariants;
  styleVariants: StyleVariantsStructure;
}): StyleVariants {
  return params.styleVariantKeys;
}
  1. Add styleVariantsKey object to the myStyles function paramsstyleVariantsKey对象添加到myStyles函数参数中
  2. Infer the type from that从中推断类型
  3. Give styleVariants the StyleVariantsStructure typestyleVariantsStyleVariantsStructure类型

This allows you to get type checking as intended, and allows you to return the inferred type from styleVariantsKey .这允许您按预期进行类型检查,并允许您从styleVariantsKey返回推断的类型。 But of course it means you have to have two of the same object, which in our case isn't too much of a problem because we don't actually need the nested styles object to be returned by myStyles , just the variant names.但当然这意味着你必须有两个相同的对象,在我们的例子中这不是什么大问题,因为我们实际上不需要myStyles返回嵌套的样式对象,只需要变体名称。 So our function call looks like this:所以我们的函数调用看起来像这样:

myStyles({
  baseStyles: {
    color: 'red',
    backgroundColor: 'red',
  },
  styleVariantKeys: {
    color: ["red"],
  },
  styleVariants: {
    color: {
      red: {
        color: 'red',
        backgroundColor: 'red',
      },
    },
  },
});

So, I spend more time on it then i expect, but here we are.所以,我花在它上面的时间比我预期的要多,但我们来了。 If you need to highlighting typo, you should based StyleVariants on AllowedStyles, for examlpe:如果您需要突出显示错别字,您应该基于 AllowedStyles 的 StyleVariants,例如:

type AllowedStyles = {
  color: 'red' | 'green';
  backgroundColor: 'red';
};

type StyleVariants = {
  [K in keyof AllowedStyles]?: AllowedStyles[K] | Partial<Record<AllowedStyles[K], Partial<AllowedStyles>>>
}

type StyleVariantsStructure = {
  baseStyles: AllowedStyles
  styleVariants: StyleVariants
}

function myStyles(params: StyleVariantsStructure):StyleVariants {
  return params.styleVariants;
}

StyleVariants based on AllowedStyles structure and values, it contains every property AllowedStyles has, but they are optioanl. StyleVariants 基于 AllowedStyles 结构和值,它包含 AllowedStyles 的所有属性,但它们是可选的。 The type of every property is provided in AllowedStyles type of property respectively OR it is an object whitch keys is each of provided types in AllowedStyles to property and its type is again AllowedStyles with all property being optional.每个属性的类型分别在 AllowedStyles 类型的属性中提供,或者它是一个对象,其键是 AllowedStyles 中提供的每个类型的属性,其类型又是 AllowedStyles,所有属性都是可选的。 Hope you get it!希望你能明白!

Typescript playground 打字稿游乐场

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM