1

Closed

Relax named parameter constraint for objects with string indexers

description

I'm trying to model Grunt config objects for DefinitelyTyped, but have run into the 0.9 constraint that objects with string indexers can only have named properties of the indexer type.


Googling has produced an entry where someone had the problem with an old jQuery declaration file, but it doesn't say what the workaround was.

Is there a workaround or is there a way this can be relaxed? Grunt MutliTask config objects have named configurations and an optional "options" property. I can't model that with this constraint. Is there another way?
Here's my example:
error:
error TS2171: All named properties must be subtypes of string indexer type 'TTaskWithFilesConfig'.

code:
interface ITaskConfig<TOptions> {
    options?: TOptions;
}

interface ITaskWithFilesConfig<TOptions> extends ITaskConfig<TOptions> {
    src: string[];
    dest?: string;
}

interface IMultiTaskConfig<TOptions, TTaskWithFilesConfig extends ITaskWithFilesConfig<TOptions>> {
    options?: TOptions;
    [task: string]: TTaskWithFilesConfig;
}
Closed Aug 12, 2013 at 6:52 PM by RyanCavanaugh
There isn't a way to type this object exactly with our current type system.

comments

kenbrubaker wrote Aug 12, 2013 at 9:49 PM

I was able to create a workaround. The key is to define the indexer as returning any, then cast to the required interface type when defining the property. I get all the intellisense goodness that way.

Task Config Base Interfaces

interface ITaskConfig<TOptions> {
    options?: TOptions;
}

interface ITaskCompactConfig<TOptions> extends ITaskConfig<TOptions> {
    src: string[];
    dest?: string;
}

interface ITaskFilesConfig<TOptions> extends ITaskConfig<TOptions> {
    files: {
        [dest: string]: string[];
    };
}

interface ITaskFilesObject {
    src: string[];
    dest?: string;
}

interface ITaskFilesArrayConfig<TOptions, TTaskFilesObject extends ITaskFilesObject> extends ITaskConfig<TOptions> {
    files: TTaskFilesObject[];
}

interface IMultiTaskConfig {
    [task: string]: any;
}

interface IMultiTaskConfig<TOptions> {
    options?: TOptions;
    [task: string]: any;
}

Uglify MultiTask declaration

interface IGruntContribUglifyConfigOptions {
    mangle?: boolean;
    compress?: boolean;
    beautify?: boolean;
    report?: any; // false / 'min' / 'gzip'
    sourceMap?: any; // String / Function 
    sourceMapRoot?: string;
    sourceMapIn?: string;
    sourceMappingURL?: any; // String / Function
    sourceMapPrefix?: number;
    wrap?: string;
    exportAll?: boolean;
    preserveComments?: any; // boolean / string / function 
    banner?: string;
}

// Backwards compatability.
interface IGruntUglifyConfig extends IGruntContribUglifyConfigOptions { }

interface ITaskGruntContribUglifyCompactConfig extends ITaskCompactConfig<IGruntContribUglifyConfigOptions> { }
interface ITaskGruntContribUglifyFilesConfig extends ITaskFilesConfig<IGruntContribUglifyConfigOptions> { }
interface ITaskGruntContribUglifyFilesArrayConfig extends ITaskFilesArrayConfig<IGruntContribUglifyConfigOptions, ITaskFilesObject> { }

interface IGruntContribUglifyConfig extends IMultiTaskConfig<IGruntContribUglifyConfigOptions> { }

Usage in Gruntfile.ts

        uglify: {
            compile: <ITaskGruntContribUglifyFilesConfig>{
                options: {
                    banner: '<%= meta.banner %>',
                },
                files: {
                    '<%= concat.compile_js.dest %>': ['<%= concat.compile_js.dest %>'],
                },
            },
        },

kenbrubaker wrote Aug 12, 2013 at 9:52 PM

Oops. Forgot this crucial snipit in the Uglify task declaration:
interface IGruntConfig {
    uglify?: IGruntContribUglifyConfig;
}