bozdoz
bozdoz

Reputation: 12860

How to use TypeScript interface overloads on an Object Method

I'm trying to conditionally return either KML or GeoJSON (string and object types respectively), and I'm wondering how to assign a function like that through an interface on an Object method.

Say the object is

const api = {
  getGeometry(url, format) {
    return fetch(`${url}?format=${format}`)
  }
}

With an interface like this:

interface GeometryRequest {
  (url: string, format: 'kml'): Promise<string>
  (url: string, format: 'geojson'): Promise<GeoJSON.FeatureCollection<any>>
}

So I can get that to work as a plain function:

const geometryRequest: GeometryRequest = (url, format) => {
  return fetch(`${url}?format=${format}`)
}

I'm just wondering how I can assign a type to an object method in a similar way.

Here are a couple of methods I tried:

getGeometry<GeometryRequest>

getGeometry: GeometryRequest

Neither are proper syntax.

I've also added a simpler version of the same problem on TypeScript Playground. In the playground output's type is: const output: string | number. But it should be able to tell the type from the overloaded functions in the interface somehow.

Any help on this syntax problem would be appreciated! :)

Upvotes: 1

Views: 510

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 249586

Function expressions can't specify multiple overloads. We can simulate the effect in one of several ways

Use a type assertion to specify the public signatures of the function

const a = {
    b: function(c) {
        if (typeof (c) === 'string') {
            return parseInt(c)
        }
        return String(c)
    } as {
        (a: string): number
        (a: number): string
    }
}

Use conditional types to decide the return type based on the input type, although this will cause issues with the implementation when returning a value (the comp will not let you assign a value because it can't determine it to be safe)

const a = {

    b<T extends string|number>(c : T ):T extends string ?number: string {
        if (typeof (c) === 'string') {
            return parseInt(c) as any
        }
        return String(c) as any
    }
}

Use a function declaration inside a self executing function and return the declared function

const a = {
    b: (function () {
        function b(a: string): number
        function b(a: number): string
        function b(c) {
            if (typeof (c) === 'string') {
                return parseInt(c)
            }
            return String(c)
        }
        return b;
    })()
}

Upvotes: 2

Related Questions