Michael_Scharf
Michael_Scharf

Reputation: 34508

How to extend a string literal type?

Given

export type Foo = 'foo' | 'bar;

How to extend the type Foo (in another module) to also allow 'x' | 'y' as possible value?

If I write somewhere else:

export type Foo = 'x' | 'y'

Typescript complains about the duplicate identifier Foo.

Upvotes: 8

Views: 8036

Answers (3)

Glorifundel
Glorifundel

Reputation: 823

if it is in a separate file you can simply rename the original foo as something else during import in the target file.

original.ts

export type Foo = 'foo' | 'bar';

target.ts

import { Foo as OriginalFoo } from './original';

export type Foo = OriginalFoo | 'x' | 'y';

now if you use the Foo definition from the target.ts file it should allow 'foo' or 'bar' or 'x' or 'y'

Upvotes: 5

Mattias Buelens
Mattias Buelens

Reputation: 20159

You can't override the existing Foo type. The reason for this is that existing code can depend on Foo being only 'foo' or 'bar'. In the example below, the type checker not only infers that a cannot be 'foo' in the else block, it can infer that a is definitely 'bar' there:

type Foo = 'foo' | 'bar';
function test(x: Foo) {
    if (x === 'foo') {
        // infers x === 'foo'
    } else {
        // infers x === 'bar'
    }
}

However, you can make a new type alias which accepts all values of the Foo type, plus some others:

type Foo = 'foo' | 'bar';
type FooEx = Foo | 'x' | 'y';

var a : FooEx;
a = 'foo'; // ok
a = 'x';   // ok
a = 'z';   // error

Upvotes: 6

michaelmesser
michaelmesser

Reputation: 3726

From TypeScript Language Specification:

An interface can have multiple merged declarations, but a type alias for an object type literal cannot.

Unfortunately, you cannot extend a type.

Upvotes: 4

Related Questions