2

I want to build an API, inspired by jest it function, which will look like this:

Typescript

interface Something {
    (param: number): void
    modifier: Something
    anotherModifier: Something
}

So I'll be able to use it like this:

s()
s.modifier()
s.anotherModifier.modifier()

If I was building it in pure JS, I'd make a few different functions, and then give them properties that would point towards one another:

const pure = (a) => {}
const modifier = (a) => {}
const anotherModifier = (a) => {}

for(const handler of [pure, modifier, anotherModifier]) {
    handler.modifier = modifier
    handler.anotherModifier = anotherModifier
}

But in TS I can't do this, as an object has to have all required properties when it's created, so I'm forced to use casts, but: (1) it is ugly, and (2) I feel like there's a much easier pattern to construct this.

So, is there a standard and type safe pattern (or library) which is commonly used to construct objects like these in Typescript? Maybe there are existing open source projects written in Typescript which can serve as example for such task?


This question is building on question about function properties — it's not duplicate, I need to do more things which are more specific.

6
  • "I need to do more things which are more specific" - what things? Can you give an example that wouldn't work with the proposed solutions? Commented May 18, 2021 at 17:00
  • @jonrsharpe I think I already did. The question I link to just adds properties, which are not self-referential. Commented May 18, 2021 at 17:12
  • 1
    I don't see why that means you can't use the same pattern of e.g. an IIFE where the return value is fully constructed. "I'm forced to use casts" - yes, because what you create initially isn't a Something. Commented May 18, 2021 at 17:15
  • @jonrsharpe my question specifically asks if there's a less ugly way. May there really isn't, which would also be an answer to my question. I can use casts, yes; but I'm used to cast things in typed languages only after making sure that no other solution exists. Commented May 18, 2021 at 18:07
  • What would "less ugly" be? That seems quite opinion-based. And it's a little disingenuous to claim your needs are more specific in some way when you just don't like it. Commented May 18, 2021 at 18:29

1 Answer 1

1

Well, i guess you can achive that with some boilerplate assignments:

interface Something {
    (param: number): void
    modifier: Something
    anotherModifier: Something
}

function getSomething(): Something {
    function anotherModifier(a: number) {}
    function something(a: number) {}
    function modifier(n: number) {}

    something.modifier = modifier
    something.anotherModifier = anotherModifier

    modifier.modifier = modifier
    modifier.anotherModifier = anotherModifier

    anotherModifier.modifier = modifier
    anotherModifier.anotherModifier = anotherModifier

    return something
}

const s = getSomething()

s(1)
s.modifier(1)
s.anotherModifier.modifier(1)

Sign up to request clarification or add additional context in comments.

1 Comment

I didn't know that Typescript compiler actually changes type of something with each line that assigns it a property, and yet I somehow considered myself a pretty advanced Typescript user. This is awesome. Thanks a lot for your answer!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.