Определение типа TypeScript для шаблона настраиваемого модуля

Я пытаюсь написать определение типа для спецификации настраиваемого модуля, которую я здесь унаследовал. Не могу понять. Уловка состоит в том, что контекст это в вычисленном контексте в функции должен управляться из характеристики, так что shouldBeValueA управляется из keyA.

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

Лучшее определение, которое у меня есть на данный момент:

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;

Но это ошибки: «Свойство keyA не существует для типа T»

Я бы сам не знал, как это сделать, но у Vue.js есть аналогичный API, и может быть полезно взглянуть на определения их типов для справки.

kingdaro 30.04.2018 23:55

Это непростой вопрос. Я думаю, что внутренний вызов this.viewModel() предотвращает вывод типа T «снизу вверх». Я немного поигрался с этим на игровой площадке и не смог заставить его работать. Либо T выводится как {}, либо кажется неразрешенным как T (как это делает ваш текущий код). Единственным обходным решением было определение model<T> вместо modelContext<T>, а затем вызов с использованием такого типа, как model<{ keyA: string }> ...

Aaron Beall 01.05.2018 04:08

Размышляя об этом сегодня, мне могут понадобиться типы более высокого порядка в машинописном тексте, которые в настоящее время не поддерживаются. То есть, если я определяю тип для самой модели представления, я получаю 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; }

Michael Wilson 01.05.2018 16:38
Зод: сила проверки и преобразования данных
Зод: сила проверки и преобразования данных
Сегодня я хочу познакомить вас с библиотекой Zod и раскрыть некоторые ее особенности, например, возможности валидации и трансформации данных, а также...
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Как заставить Remix работать с Mantine и Cloudflare Pages/Workers
Мне нравится библиотека Mantine Component , но заставить ее работать без проблем с Remix бывает непросто.
Угловой продивер
Угловой продивер
Оригинал этой статьи на турецком языке. ChatGPT используется только для перевода на английский язык.
TypeScript против JavaScript
TypeScript против JavaScript
TypeScript vs JavaScript - в чем различия и какой из них выбрать?
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Синхронизация localStorage в масштабах всего приложения с помощью пользовательского реактивного хука useLocalStorage
Не все нужно хранить на стороне сервера. Иногда все, что вам нужно, это постоянное хранилище на стороне клиента для хранения уникальных для клиента...
Что такое ленивая загрузка в Angular и как ее применять
Что такое ленивая загрузка в Angular и как ее применять
Ленивая загрузка - это техника, используемая в Angular для повышения производительности приложения путем загрузки модулей только тогда, когда они...
3
3
100
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я не уверен, что это поможет кому-то еще, но @kingdaro прав, что этот шаблон очень похож на API vue.js. В конце концов я построил определение типа, вдохновленное этим шаблоном.

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
    }
}

Это все еще не совсем идеально, но это был хороший опыт обучения адаптации типов vue к этой структуре модели представления.

Другие вопросы по теме