#Getting intersection type as argument instead of expected union type

12 messages · Page 1 of 1 (latest)

wide leaf
#

I have this code:

async function updateMysql({config}: {config: {
    name: string;
  }}) {}

async function updateMongo({config}: {config: {datasourceName: string;} }) {}

type Configs = {
mysql: {
    name: string;
},
mongodb: {
    datasourceName: string;
}
}

const dbTypes = [
    {
        type: 'mysql',
        caller: updateMysql
    },
    {
        type: 'mongodb',
        caller: updateMongo
    }
]

function processConfig(config: Configs[keyof Configs], dbType: keyof Configs) {
    const typeConfig = dbTypes.find(({type}) => type === dbType)!;
    if (dbType === 'mysql'){
      typeConfig.caller({config: config as Configs['mysql']});
    } else {
        typeConfig.caller({config: config as Configs['mongodb']});
    }    
}

but I'm getting this error:

Type '{ datasourceName: string; }' is not assignable to type '{ name: string; } & { datasourceName: string; }'.
  Property 'name' is missing in type '{ datasourceName: string; }' but required in type '{ name: string; }'.(2322)
input.tsx(2, 5): 'name' is declared here.
input.tsx(1, 39): The expected type comes from property 'config' which is declared here on type '{ config: { name: string; }; } & { config: { datasourceName: string; }; }'
(property) config: {
    name: string;
} & {
    datasourceName: string;
}

I would have thought that config would be a union type and not an intersection type. how would I fix this? General improvements are also welcome

warm rivet
#

i've refactored it a bit since the way you had it structured wasn't great for having the right types, but this has the same functionality as what you seem to want from the code you've provided:

sleek laurelBOT
#
littlelily#0

Preview:```ts
type Configs = {
mysql: {
name: string
}
mongodb: {
datasourceName: string
}
}

type Callers = {
[K in keyof Configs]: ({
config,
}: {
config: Configs[K]
}) => void
}

const callers: Callers = {
mysql: ({config}: {config: {name: string}}) => {},
mongodb: (
...```

wide leaf
#

thank you very much!

wide leaf
#

I tried to apply this:

import React from 'react';
import {useState} from 'react';

type Configs = {
  mysql: {
      datasourceName: string;
      host: string;
      port: string;
      databaseName: string;
      username: string;
      password: string;
    },
  mongodb: {
      accessKeyId: string;
      secretAccessKey: string;
      region: string;
      datasourceName: string;
    }
}

type Callers = {
  [K in keyof Configs]: ({
    config,
  }: {
    config: Configs[K]
  }) => void
}

const callers: Callers = {
  mysql: ({config}: {config: Configs['mysql']}) => {},
  mongodb: ({config}: {config: Configs['mongodb']}) => {},
}

async function updateMysql({config}: {config: Configs['mysql']}) {}

async function updateMongo({config}: {config: Configs['mongodb'] }) {}

const datasources = [
  {
    type: "mongodb",
    
    form: MongoForm,
    default: {
      accessKeyId: "",
      secretAccessKey: "",
      region: "",
      datasourceName: "",
    },
  },
  {
    type: "mysql",
    form: MySQLForm,
    default: {
      datasourceName: "",
      host: "",
      port: "",
      databaseName: "",
      username: "",
      password: "",
      workspaceId: "",
    },
  },
] as const;

function DatabaseModal({dbType}: {dbType: keyof Configs}){
    const datasource = datasources.find(({type}) => type === dbType)!;
    const [config, setConfig] = useState(datasource.default);
    const handleDataChange = (
    k: keyof Configs[keyof Configs],
    value: string
    ) => {
        // ...
    };
    async function handleSave(dbType: keyof Configs) {
        if (datasource.type === 'mongodb'){
            await callers['mongodb']({
                config: config as Configs['mongodb'],
            });
        } else {
            await callers['mysql']({
                config:  config as Configs['mysql'],
            });
        }    
    }

    return (
        <div>
            <datasource.form data={config} setData={handleDataChange} />
        </div>
    )
}
#
type FormProps = {
  data: Configs[keyof Configs];
  setData: (
    path: keyof Configs[keyof Configs],
    value: string
  ) => void;
}

function MongoForm(props: FormProps) {
    return <form></form>
}

function MySQLForm(props: FormProps) {
    return <form></form>
}

but am getting another error

/*
Type '(path: keyof Configs[keyof Configs], value: string) => void' is not assignable to type '(path: "accessKeyId" | "secretAccessKey" | "region" | "datasourceName", value: string) => void'.
  Types of parameters 'path' and 'path' are incompatible.
    Type '"accessKeyId" | "secretAccessKey" | "region" | "datasourceName"' is not assignable to type '"datasourceName"'.
      Type '"accessKeyId"' is not assignable to type '"datasourceName"'.ts(2322)
index.tsx(82, 3): The expected type comes from property 'setData' which is declared here on type 'IntrinsicAttributes & { data: { accessKeyId: string; secretAccessKey: string; region: string; datasourceName: string; }; setData: (path: "accessKeyId" | "secretAccessKey" | "region" | "datasourceName", value: string) => void; }'
(property) setData: (path: "accessKeyId" | "secretAccessKey" | "region" | "datasourceName", value: string) => void
*/

not with the code above per se but the original, which I tried to pare down here

warm rivet
#

not sure why you keep trying to structure your data as an array of objects instead of just objects like I showed in my previous example, but here's a refactored version of your code again showing the full thing.

sleek laurelBOT
#
littlelily#0

Preview:```ts
import React from "react"
import {useState} from "react"

type FormProps<T extends keyof Configs> = {
data: Configs[T]
setData: <U extends Configs[T], V extends keyof U>(
path: V,
value: U[V]
) => void
}

function MongoForm(props: FormProps<"mongodb">)
...```

warm rivet
#

you seem to not quite understand how to use generics, so I'd receommend reading up some more on those

#

if you dont use generics, you just end up with unions of all the possible types everywhere, which isnt what you want.

warm rivet
# sleek laurel

small correction, line 63 is supposed to say // put updateMySQL logic here

#

you dont need separately defined functions for those updateMongo and updateMySQL functions, they can just go in your datasources object like shown there, which also means they're properly type checked too