From 4db25cf3f11edeea2aa18bc1a7cc5613acf755b6 Mon Sep 17 00:00:00 2001 From: HowardRichards Date: Mon, 2 Mar 2015 12:21:01 +0000 Subject: [PATCH] Refactored knockout components Previous Knockout component registration code was complicate since union types did not exist in TypeScript. The knockout.d.ts file has already had changes for union types added, so I have refactored my original changes to component.register to use this. Revert "Refactored knockout.register for union types" This reverts commit 920b8d64621f249331f2a17123148c446c212d32. Refactored knockout.register for union types Removed number of interfaces for ko.register methods and simplified using union types for clarity. Refactored component types into a namespace to reduce namespace pollution --- knockout/knockout.d.ts | 158 +++++++++++++++---------------- knockout/tests/knockout-tests.ts | 52 +++++----- 2 files changed, 102 insertions(+), 108 deletions(-) diff --git a/knockout/knockout.d.ts b/knockout/knockout.d.ts index 28d7b94cc4..f4838c411d 100644 --- a/knockout/knockout.d.ts +++ b/knockout/knockout.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Knockout v3.2.0-beta +// Type definitions for Knockout v3.2.0 // Project: http://knockoutjs.com // Definitions by: Boris Yankov , Igor Oleinikov , Clément Bourgeois // Definitions: https://github.com/borisyankov/DefinitelyTyped @@ -559,92 +559,88 @@ interface KnockoutBindingProvider { getBindingAccessors?(node: Node, bindingContext: KnockoutBindingContext): { [key: string]: string; }; } -interface KnockoutComponents { - // overloads for register method: - register(componentName: string, config: KnockoutComponentRegister): void; - register(componentName: string, config: KnockoutComponentRegisterStringTemplate): void; - register(componentName: string, config: KnockoutComponentRegisterFnViewModel): void; - register(componentName: string, config: KnockoutComponentRegisterStringTemplateFnViewModel): void; - register(componentName: string, config: KnockoutComponentRegisterAMD): void; - register(componentName: string, config: {}): void; - - isRegistered(componentName: string): boolean; - unregister(componentName: string): void; - get(componentName: string, callback: (definition: KnockoutComponentDefinition) => void): void; - clearCachedDefinition(componentName: string): void - defaultLoader: KnockoutComponentLoader; - loaders: KnockoutComponentLoader[]; - getComponentNameForNode(node: Node): string; -} - -/* interfaces for register overloads*/ - -interface KnockoutComponentRegister { - template: KnockoutComponentTemplate; - viewModel?: KnockoutComponentConfigViewModel; -} - -interface KnockoutComponentRegisterAMD { - // load self-describing module using AMD module name - require: string; -} - -interface KnockoutComponentRegisterFnViewModel { - template: KnockoutComponentTemplate; - viewModel?: (params: any) => any; -} - -interface KnockoutComponentRegisterStringTemplate { - template: string; - viewModel?: KnockoutComponentConfigViewModel; -} - -interface KnockoutComponentRegisterStringTemplateFnViewModel { - template: string; - viewModel?: (params: any) => any; -} - -interface KnockoutComponentConfigViewModel { - instance?: any; - createViewModel? (params?: any, componentInfo?: KnockoutComponentInfo): any; - require?: string; -} - -interface KnockoutComponentTemplate { - // specify element id (string) or a node - element?: any; - // AMD module load - require?: string; -} - -interface KnockoutComponentInfo { - element: Node; -} -/* end register overloads */ -interface KnockoutComponentDefinition { - template: Node[]; - createViewModel?(params: any, options: { element: Node; }): any; -} - -interface KnockoutComponentLoader { - getConfig? (componentName: string, callback: (result: KnockoutComponentConfig) => void): void; - loadComponent? (componentName: string, config: KnockoutComponentConfig, callback: (result: KnockoutComponentDefinition) => void): void; - loadTemplate? (componentName: string, templateConfig: any, callback: (result: Node[]) => void): void; - loadViewModel? (componentName: string, viewModelConfig: any, callback: (result: any) => void): void; - suppressLoaderExceptions?: boolean; -} - -interface KnockoutComponentConfig { - template: any; - createViewModel?: any; -} - interface KnockoutComputedContext { getDependenciesCount(): number; isInitial: () => boolean; isSleeping: boolean; } +// +// refactored types into a namespace to reduce global pollution +// and used Union Types to simplify overloads (requires TypeScript 1.4) +// +declare module KnockoutComponentTypes { + + interface Config { + viewModel: ViewModelFunction | ViewModelSharedInstance | ViewModelFactoryFunction | AMDModule; + template: string | Node[]| DocumentFragment | TemplateElement | AMDModule; + } + + interface ComponentConfig { + template: any; + createViewModel?: any; + } + + interface EmptyConfig { + } + + // common AMD type + interface AMDModule { + require: string; + } + + // viewmodel types + interface ViewModelFunction { + (params?: any): any; + } + + interface ViewModelSharedInstance { + instance: any; + } + + interface ViewModelFactoryFunction { + createViewModel: (params?: any, componentInfo?: ComponentInfo) => any; + } + + interface ComponentInfo { + element: any; + } + + interface TemplateElement { + element: string | Node; + } + + interface Loader { + getConfig? (componentName: string, callback: (result: ComponentConfig) => void): void; + loadComponent? (componentName: string, config: ComponentConfig, callback: (result: Definition) => void): void; + loadTemplate? (componentName: string, templateConfig: any, callback: (result: Node[]) => void): void; + loadViewModel? (componentName: string, viewModelConfig: any, callback: (result: any) => void): void; + suppressLoaderExceptions?: boolean; + } + + interface Definition { + template: Node[]; + createViewModel? (params: any, options: { element: Node; }): any; + } +} + +interface KnockoutComponents { + // overloads for register method: + register(componentName: string, config: KnockoutComponentTypes.Config | KnockoutComponentTypes.EmptyConfig): void; + + isRegistered(componentName: string): boolean; + unregister(componentName: string): void; + get(componentName: string, callback: (definition: KnockoutComponentTypes.Definition) => void): void; + clearCachedDefinition(componentName: string): void + defaultLoader: KnockoutComponentTypes.Loader; + loaders: KnockoutComponentTypes.Loader[]; + getComponentNameForNode(node: Node): string; +} + + + + + declare module "knockout" { export = ko; } diff --git a/knockout/tests/knockout-tests.ts b/knockout/tests/knockout-tests.ts index 78d464f073..b14ce073c4 100644 --- a/knockout/tests/knockout-tests.ts +++ b/knockout/tests/knockout-tests.ts @@ -604,52 +604,50 @@ function test_allBindingsAccessor() { }; } + function test_Components() { + // test all possible ko.components.register() overloads function test_Register() { - // test all possible ko.components.register() overloads + // reused parameters var nodeArray = [new Node, new Node]; var singleNode = new Node; + var viewModelFn = function (params: any) { return null; } - // ------- string-templates with different viewmodel overloads: + // ------- viewmodel overloads: - // string template and inline function (commonly used in examples) - ko.components.register("name", { template: "string-template", viewModel: function (params) { return null; } }); + // viewModel as inline function (commonly used in examples) + ko.components.register("name", { template: "string-template", viewModel: viewModelFn }); - // string template and instance vm + // viewModel from shared instance ko.components.register("name", { template: "string-template", viewModel: { instance: null } }); - // string template and createViewModel factory method - ko.components.register("name", { template: "string-template", viewModel: { createViewModel: function (params: any, componentInfo: KnockoutComponentInfo) { return null; } } }); + // viewModel from createViewModel factory method + ko.components.register("name", { template: "string-template", viewModel: { createViewModel: function (params: any, componentInfo: KnockoutComponentTypes.ComponentInfo) { return null; } } }); - // string template and require module vm + // viewModel from an AMD module ko.components.register("name", { template: "string-template", viewModel: { require: "module" } }); - // ------- non-string templates + // ------- template overloads - // viewmodel as function and four types of template - ko.components.register("name", { template: { element: "elementID" }, viewModel: function (params) { return null; } }); - // Node template for element and inline function (commonly used in examples) - ko.components.register("name", { template: { element: singleNode }, viewModel: function (params) { return null; } }); - // object template for element and inline function (commonly used in examples) - ko.components.register("name", { template: nodeArray, viewModel: function (params) { return null; } }); - // object template for element and inline function (commonly used in examples) - ko.components.register("name", { template: { require: "module" }, viewModel: function (params) { return null; } }); - - // viewmodel as object, and four types of non-string tempalte - ko.components.register("name", { template: { element: "elementID" }, viewModel: { instance: null } }); - // Node template for element and inline function (commonly used in examples) - ko.components.register("name", { template: { element: singleNode }, viewModel: { instance: null } }); - // object template for element and inline function (commonly used in examples) - ko.components.register("name", { template: nodeArray, viewModel: { instance: null } }); - // object template for element and inline function (commonly used in examples) - ko.components.register("name", { template: { require: "module" }, viewModel: { instance: null } }); + // template from named element + ko.components.register("name", { template: { element: "elementID" }, viewModel: viewModelFn }); + + // template using single Node + ko.components.register("name", { template: { element: singleNode }, viewModel: viewModelFn }); + + // template using Node array + ko.components.register("name", { template: nodeArray, viewModel: viewModelFn }); + + // template using an AMD module + ko.components.register("name", { template: { require: "text!module" }, viewModel: viewModelFn }); // Empty config for registering custom elements that are handled by name convention - ko.components.register('name', { /* No config needed */ }); + ko.components.register('name', { /* No config needed */ }); } } + function testUnwrapUnion() { var possibleObs: KnockoutObservable | number;