最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to use Union Types in TypeScript - Stack Overflow

programmeradmin1浏览0评论

I'm using typescript on a project and in some parts of it I have to use union types. But I'm getting some weird error messages that I don't know how to deal with. Consider the type below:

type body = {
  [_: string]:
    | 'boolean'
    | 'number'
    | 'string'
    | {
        type: 'boolean' | 'number' | 'string'
        optional?: boolean
      }
    | {
        type: 'array'
        items: 'boolean' | 'string' | 'number'
        optional?: boolean
        [_: string]: any
      }
}

I'm using [_: string]: because I should be able to use any arbitrary key. The value can either be a string indicating a type or can be a object that provides more details. Now consider the following function:

function show(data: body) {
  console.log(data)
}

When I call the above function with the object below:

const data = {
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
}

Typescript gives the error below:

Argument of type '{ username: { type: string; optional: boolean; }; address: { type: string; }; city: string; }' is not assignable to parameter of type 'body'.

Property 'username' is inpatible with index signature.

Type '{ type: string; optional: boolean; }' is not assignable to type '"string" | "number" | "boolean" | { type: "string" | "number" | "boolean"; optional?: boolean | undefined; } | { [_: string]: any; type: "array"; items: "string" | "number" | "boolean"; optional?: boolean | undefined; }'.

Property 'items' is missing in type '{ type: string; optional: boolean; }' but required in type '{ [_: string]: any; type: "array"; items: "string" | "number" | "boolean"; optional?: boolean | undefined; }'.

How can I solve this? thanks

I'm using typescript on a project and in some parts of it I have to use union types. But I'm getting some weird error messages that I don't know how to deal with. Consider the type below:

type body = {
  [_: string]:
    | 'boolean'
    | 'number'
    | 'string'
    | {
        type: 'boolean' | 'number' | 'string'
        optional?: boolean
      }
    | {
        type: 'array'
        items: 'boolean' | 'string' | 'number'
        optional?: boolean
        [_: string]: any
      }
}

I'm using [_: string]: because I should be able to use any arbitrary key. The value can either be a string indicating a type or can be a object that provides more details. Now consider the following function:

function show(data: body) {
  console.log(data)
}

When I call the above function with the object below:

const data = {
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
}

Typescript gives the error below:

Argument of type '{ username: { type: string; optional: boolean; }; address: { type: string; }; city: string; }' is not assignable to parameter of type 'body'.

Property 'username' is inpatible with index signature.

Type '{ type: string; optional: boolean; }' is not assignable to type '"string" | "number" | "boolean" | { type: "string" | "number" | "boolean"; optional?: boolean | undefined; } | { [_: string]: any; type: "array"; items: "string" | "number" | "boolean"; optional?: boolean | undefined; }'.

Property 'items' is missing in type '{ type: string; optional: boolean; }' but required in type '{ [_: string]: any; type: "array"; items: "string" | "number" | "boolean"; optional?: boolean | undefined; }'.

How can I solve this? thanks

Share edited Dec 20, 2023 at 15:06 Penny Liu 17.6k5 gold badges86 silver badges108 bronze badges asked Jun 9, 2021 at 18:10 massivefermionmassivefermion 6751 gold badge10 silver badges25 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 4

You can explictly declare what type your property data is

const data: body = {
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
}

or cast it

const data = {
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
} as body;

The issue here is with an overly broad inference on the type of the data variable. Take a look at the reproduction here.

If you hover your data variable, you'll note that it was given the inferred type:

{
    username: {
        type: string;
        optional: boolean;
    };
    address: {
        type: string;
    };
    city: string;
}

Breaking down your error message, we see the first line:

Property 'username' is inpatible with index signature.

Indicates that username is the issue here. As you can see from the inferred type, that property has the type {type: string, optional: boolean}.

You might think that this would match to the

{ type: 'boolean' | 'number' | 'string', optional?: boolean }

part of your union, however the critical difference is that this part of your union requires the type property to have one of the literal string types 'boolean' | 'number' | 'string', and does not permit any string (represented by the type string (without quotes)).

This is why it then tries to match to the final piece of your union, which would allow the type: string key/value pair due to the index signature. But this last part of the union also requires an Items property which is what is leading to the specific error you see.


So how do you fix it? Well you need to give typescript a hint that the username.type property of your data object is not just any string. Here are some various ways:

  • Use an explicit declaration or cast, using the body type, as in Andreas' excellent answer.
  • Cast just that property's value: type: 'string' as 'string'. You'd have to do this for all three properties so this is not very ideal in this particular case.
  • Declare the entire object as a const: const data = { ... } as const
  • Or just use the object inline instead of declaring it first:
show({
  username: { type: 'string', optional: false },
  address: { type: 'string' },
  city: 'string'
});
发布评论

评论列表(0)

  1. 暂无评论