3

I'm trying to write a type definition for a custom built module specification I've inherited here. Cannot figure it out. The trick is that the this context in the computed context in functions should be driven from properties such that shouldBeValueA is driven from keyA.

define.model("moduleName",
[
    "jquery"
],
function($) {
    return this.viewModel({
        pub: {
            properties: {
                keyA: "valueA"
            },
            functions: {
                keyB: this.computed(function() {
                    var shouldBeValueA = this.keyA;
                })
            }
        }
    })
})

Best definition I've got so far:

interface Define {
model: (
    name: string,
    dependencies: string[],
    moduleContext: <T>(this: {
        computed: (context: (this: T) => any) => KnockoutComputed<any>,
        viewModel: (options: {
            pub: {
                properties: T,
                functions: any
            },
        }) => any;
    },
    ...args) => void) => void;
}

declare var define: Define;

But this errors: "Property keyA does not exist on type T"

3
  • I wouldn't know how to do this myself, but Vue.js has a similar API, and it might help to look at their type definitions for reference Commented Apr 30, 2018 at 21:55
  • This is a tricky one. I think the inner call to this.viewModel() is preventing the type T from being inferred "upward". I played with this in the Playground a bit and couldn't get it to work. Either T is inferred as {} or it seems to be unresolved as T (as your current code does). Only workaround was to define model<T> instead of modelContext<T>, then call using a type like model<{ keyA: string }>... Commented May 1, 2018 at 2:08
  • Thinking about this more today, I might need higher kinded types in typescript which are currently not supported. That is, if I define a type for the viewmodel itself I get type viewModel<T> = (options: { pub: { properties: T, functions?: any }, }) => any interface Define { model: ( name: string, dependencies: string[], moduleContext: <A, F extends viewModel<A>>(this: { computed: (context: (this: A) => any) => KnockoutComputed<any>, viewModel: F }, ...args) => any) => any; } Commented May 1, 2018 at 14:38

1 Answer 1

1

I'm not sure if this will help anybody else, but @kingdaro is correct that this pattern is very similar to the vue.js API. I eventually built a type definition inspired by that pattern.

interface RequireDefine {
    model<TPubProps, TPubFuncs, TPrivProps, TPrivFuncs>(
        name: string,
        deps: string[],
        factory: (
            this: {
                viewModel<TPubProps, TPubFuncs, TPrivProps, TPrivFuncs>(
                    options: ThisTypedViewModelOptions<TPubProps, TPubFuncs, TPrivProps, TPrivFuncs>
                ): TPubProps & TPubFuncs
    ): any
}

type ThisTypedViewModelOptions<TPubProps, TPubFuncs, TPrivProps, TPrivFuncs> =
    object
    & ViewModelOptions<TPubProps, TPubFuncs, TPrivProps, TPrivFuncs>
    & ThisType<CombinedViewModelInstance<TPubProps, TPubFuncs, TPrivProps, TPrivFuncs>>

type CombinedViewModelInstance<TPubProps, TPubFuncs, TPrivProps, TPrivFuncs> = TPubProps & TPubFuncs & { priv: () => TPrivProps & TPrivFuncs }    

type DefaultMethods = { [key: string]: (...args: any[]) => any };

interface ViewModelOptions<
    TPubProps = object,
    TPubFuncs = DefaultMethods,
    TPrivProps = object,
    TPrivFuncs = DefaultMethods
    > {

    ctor?: (options?: any) => void,
    pub?: {
        properties?: TPubProps,
        functions?: TPubFuncs
    },
    priv?: {
        properties?: TPrivProps,
        functions?: TPrivFuncs
    }
}

It's still not completely perfect, but it was a good learning experience adapting the vue types to this viewmodel structure.

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

Comments

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.