#Intersection type is overridden by mapped type

28 messages · Page 1 of 1 (latest)

rare owl
#
interface Config {
    translations: ConfigTranslations
}


type ConfigTranslations =   {
    $load?: {
        groups: string[]
        routes: string[]
    }[]
    $directory?: {
        main?: string
        pages?: string
    }
} & {
    [group: string]: {
        [locale: string]: DeepStringRecord
    }
}

type DeepStringRecord = {
    [key: string]: string | DeepStringRecord
}

const config: Config = {
    translations: { // Type '{ routes: string[]; groups: string[]; }[]' is not assignable to type '{ [locale: string]: DeepStringRecord; }'
        $load: [
            {
                routes: ["/group$"],
                groups: ["^group"],
            },
            {
                routes: ["/group"],
                groups: ["^group2"],
            },
        ],
        common: {
            en: {
                foo: "bar",
                bar: {
                    baz: "foo",
                },
            },
        }
    }
}

I typed ConfigTranslations, so it can have 2 special keys but the mapped type overrides these keys and throws an error when trying to fill them. Do you have an idea on how to fix this ?

TS Playground:
https://www.typescriptlang.org/play?ssl=6&ssc=6&pln=6&pc=24#code/JYOwLgpgTgZghgYwgAgMIHsQ2Ac2QbwCgBIMKOEAZwBs4xhNKAuNTbHAFXKtvscIC+hYWACeABxQYsuLhRp0GVZAF5k6osQAk1dHAAmAfhabiOKOgCu45skplQOANoBdEsQuXIt+1EeuSAQDtfWAoCAQwdChRYwJ3AFs4UDjfR3dxOBwISlSHEBxAwWQAMnjiJ3MrcRY0gpcTdyddBDhqCFr8nAbkABEICHEAZS6AJQjo-SKhQjFJPoHhsYmofVVypwBrCFFOv3q9x2QAHwXBkf2ccYRJwWEbqjBkB-YWaXZ1onV1MnleJVs+GQAHpgcgOBIUAByIGebyHAquADcyCq1h8XWRyCCLihyGAlGQIHQTzglEouBAcAARu1kFF6ZDkDDkM10K12gjuix+udljdViiBFD3Do9PoWE53MRTMQPFZ4ayAETAtHiLRKlwAGmlZk8NklSoAemrNTq5cQBOa5bL5V4cobVfqzbq1bYnMa1QAmF0Wq3ubXuG4JBKYRoWiAgcMWmDodAsJXUuBQJXWuVJqDRi1JgBeCdj6FTuv9fp133L2MI5aEAiAA

finite tulip
#

!gerrit0:index-signatures

worthy sandBOT
#
gerrit0#0
`!gerrit0:index-signatures`:

Index signatures apply to all members of the type that match the signature. Therefore, the following type is invalid, even though TypeScript does not detect it until you actually try to construct a value which conforms to the type.

type Foo = { a: 1 } & { [x: string]: 2 }

TypeScript does not have a way to specify "everything besides defined keys" since it does not have negated types. This pattern cannot be expressed in TypeScript today. A more TS-friendly version of it puts all of the extra properties on a dedicated key:

type Foo = { a: 1; extra: { [x: string]: 2 } }

negated types: https://github.com/microsoft/TypeScript/pull/29317

rare owl
#

so it cannot be done ?

supple cliff
#

can you know all of the groups ahead of time?

#

besides 'common', what others are there?

rare owl
#

@supple cliff unfortunately they are dynamic

#

I have no way to know them ahead of time they are user defined

#

(this is for an npm library)

supple cliff
#

but they are knowable statically in the consumer's codebase?

#

(if so you can probably make it generic)

rare owl
#

a node algorythm parses them from the FS

supple cliff
#

either way i still might suggest to change the structure though as suggested by that snippet. that way it's no problem if a user happens to have a group named '$load', for example

rare owl
supple cliff
#

i mean sure you could just type everything as any or unknown or something almost as wide that encompasses every property value, but i don't think you'd want that

#

what would happen at runtime if somebody does end up using '$load' as a group? your code has to handle that somehow

rare owl
supple cliff
#

are there any other rules you enforce upon group names besides that they cannot be '$load' or '$directory'?

rare owl
#

no that's it

#

only these 2

supple cliff
#

too bad. if there was some other way they were provably-distinct from those two strings (say, they have to start with a letter) then you could make this structure work

#

maybe this doesn't make sense, but could you move $load and $directory out of translations? like put them at the top level of Config

#

that way you avoid another level of nesting

rare owl
#

if there's no other solutions

supple cliff
#

cool

rare owl
#

thanks for your help