Home > Blockchain >  What is the purpose of `string & {}`
What is the purpose of `string & {}`

Time:01-28

I was trying to typehint the gridTemplateColumns css property, and in a dependency of React called csstype I found the following property definition:

  gridTemplateColumns?: Property.GridTemplateColumns<TLength> | undefined;

This is a property of the following interface, where TLength and TTime are declared.

export interface StandardLonghandProperties<TLength = (string & {}) | 0, TTime = string & {}> {

I don't understand what string & {} is trying to accomplish. How is it different than just a regular string?

CodePudding user response:

Because the so-called empty object type {} only excludes null and undefined (see How to undestand relations between types any, unknown, {} and between them and other types?), the intersection string & {} is equivalent to string in terms of what values it accepts. So for most purposes there is no difference between string and string & {} and thus no reason to use the more complicated type.

But even though string & {} might be considered the same as string, the compiler does not eagerly reduce the former to the latter, the way it does for, say, string & unknown (where the unknown type is absorbed by the intersection with string), or the way it does for union types like string | "x" (where the string literal type "x" is absorbed by the union with string).

So one use of string & {} is to prevent some of these eager reductions for IntelliSense autosuggest/autocomplete and documentation purposes. The type (string & {}) | "x" allows the same values as string, but still has enough "memory" of the "x" type for it to be suggested by an IntelliSense-enabled IDE. This technique is mentioned in microsoft/TypeScript#29729 as a workaround for the lack of native support for autocompletion of string literal unions with string.


Still, in the case of (string & {}) | 0 and string & {} as shown in the definition for the StandardLonghandProperties interface in frenic/csstype, it seems unmotivated. There's no difference in the IntelliSense you'd be prompted with for (string & {}) | 0 and just string | 0 (since 0 is a numeric literal it doesn't get absorbed in the union), and there's definitely no difference in the IntelliSense prompting for string & {} and just string, since there are no literals to suggest at all.

So, why is it like that? If you look at the frenic/csstype#73 issue, it seems that there are a bunch of places that do use a union of string literals with string, where IntelliSense suffered. Apparently frenic/csstype has its its own build system to generate the TypeScript declaration file. So the fix in frenic/csstype#74 was to just change the generation code so that instead of just string and number types, it would generate (string & {}) and (number & {}).

That means there really isn't much of a reason for string & {} in the code you're looking at. If the maintainers of frenic/csstype wanted to, they could change the code so that string and number are left alone in places where they are not part of a union with literals of the same base type. That is, they could make sure that & {} only shows up in places where it improves IntelliSense suggestions.

But that would take more work. And while such a change might reduce the sort of confusion that prompted this question, it's not like the current code has a bug. Instead, it's a (mostly) harmless side-effect.

  • Related