how to fix typescript error

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']});
}
}
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;
}
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;
}
how would I fix this? I would have thought that config would be a union type and not an intersect type
6 Replies
Tom
Tom12mo ago
ts isnt smart enough to know dbType and typeConfig.type are the same therefore typeConfig isnt discriminated as a side note it seems like youre trying to get fancy with ts typing. my experience with that has been..... frustrating. TS lets you describe a ton of things in compile-time types but: 1) the typings themselves arent always elegant or readable to most people 2) types that are too restrictive can require writing your code in a more convoluted way in order for the compile-time checks to work 3) getting the types really really correct can take a long time its possible im just not that good at ts, but this has been my overal experience trying to get ts to do more than just checking structure
alan
alan12mo ago
thank you so much! I'd be all for a simpler less fancy way if possible. this is the version that I just landed on. I updated it to this and am now having another issue:
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;
}
}

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

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

const datasources = [
{
type: "mongodb",
caller: updateMongo,
form: MongoForm,
default: {
accessKeyId: "",
secretAccessKey: "",
region: "",
datasourceName: "",
},
},
{
type: "mysql",
caller: updateMysql,
form: MySQLForm,
default: {
datasourceName: "",
host: "",
port: "",
databaseName: "",
username: "",
password: "",
workspaceId: "",
},
},
] as const;
type FormType = React.ComponentType<{
data: Configs[keyof Configs];
setData: (
path: keyof Configs[keyof Configs],
value: string
) => void;
}>;
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 datasource.caller({
config: config as Configs['mongodb'],
});
} else {
await datasource.caller({
config: config as Configs['mysql'],
});
}
}

return (
<div>
<datasource.form data={config} setData={handleDataChange} />
</div>
)
}
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;
}
}

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

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

const datasources = [
{
type: "mongodb",
caller: updateMongo,
form: MongoForm,
default: {
accessKeyId: "",
secretAccessKey: "",
region: "",
datasourceName: "",
},
},
{
type: "mysql",
caller: updateMysql,
form: MySQLForm,
default: {
datasourceName: "",
host: "",
port: "",
databaseName: "",
username: "",
password: "",
workspaceId: "",
},
},
] as const;
type FormType = React.ComponentType<{
data: Configs[keyof Configs];
setData: (
path: keyof Configs[keyof Configs],
value: string
) => void;
}>;
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 datasource.caller({
config: config as Configs['mongodb'],
});
} else {
await datasource.caller({
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>
}

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

/*
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
*/
the thing is the code as is has no errors but the version that this is based off of is failing
Tom
Tom12mo ago
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.
Tom
Tom12mo ago
(next time make it a ts playground so its easier to look at btw)
alan
alan12mo ago
ah, thank you. I found a way to repro the issue here: https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wG4AoUSWOAbwFcBnJAZRhRiQF85tcCi6GGXLkYATzBI4AYQgA7TMADmjOAF465OHBDjGARwA2ALi06LcACYcUjCPShokAORQgkZxjCjB5yiksdAAsIby8fPwDtIOoYCN9-QKCbdgAjO1d3TzhvROiguCYkKHlshKjkyzA7RgB3aCsKpJidLgAaGJAFZQgrNLNaVot0Z0ZGAGkkcQBJJtzIlsLmNCIYAEE0Mcnp5oKgomVgBT2qi1S7Bycsj1PhrnIHsUlpGRQjIxK1TSGdAG0JnA-HAANbTCCYWQKJSqAC6ZgAFL8LGhoSpOm1BsNUYoVGY5LjVADYTEuABKDQAPjgADcIMArI9RDjvHA0O9PlBGPiOV8NOZdPpjIjaDiYVxBmK8VDCYw-vg9IYjPhYeSqXQOl0en0BnAkVLlBK6Ab8WiiQrtf0VWr1NTaJqnnZxPI0Lx6C6YMd5EUwKkkABZIVGfVmo2is2m2XyxXGa0U+2iJ0ut0er0+v3+7Uhwlhk0ymFyi3+HUquBqhPkFnwC72Rxjfl-GLInQSKRmABE3WL-XbGIsw0w0BAZkzxYAYkO+zorEhMCh6EZ4gLLKMkOMprN5u3e8MdCs1ptthuOzvCocvSep+dbLXrm5bnBt1fNW0+824K2cp2g6eLIOoMOcCBiwACKAAyE4AVeM5zguS7vtON5XM495fr+lihOEj7oRYcSXru1i2BkzCofhhTFKU5TYVeOg1OMDRQFuOE6AxIKMDUzhzGRFgvmWnSwnAdhsgo3gUOQmDuhgaYACJEZkmY2MGtD9AAKi8YaqS8ZhguIEL5iojDku+VaEewt7OPyNbIWuAB0SjyFYCJIp+NrUp+GjqJomlSGSACEZwmX8BrtLkSAwASMICZoxRsBwSAIlZdZIDZMHzouZIBSJ8DBCgDmfLJ7AyDl-jSJoCLDCC2ngpCEUGX8Ol6bVcJXjS7z0DkeRRMMFK2suQQAPT9XANkjfcZxJq6EmpgocDFVYnwsCgNLxd5OQNTVZqMPGBE6MAkIJUhSU2e5nmaEWvRWmSCGFIJdQoMA8Dsh8XzRpaaQqkiO03ToeYGoJahNYWXYXe9sI0Td5JnJYPBIEYzB9d9KB3Q9bK8ly0ZBh913fT9Ea44S-36eaMbKmDX3QxlX08P20OiJYayON65XfQAPFYwA0pS5MWGzh3XHZQ6mSg6jhjmoUwAVwu0HN+W2EVuXKNwcD9VzrP9eznPdUyzxSHAkEgAACjgYDfAKFyRgW9XVUTjCwskzAS7YiLDDUMDBFVukbVG6022TlitUY7V7DEPXUnSDIUE8U1STNo69PrCJgMb3J60ORsQCb22WCZ54zZoScZ4wNkO5LCKEEgRwKPgIX4PYHhwLn8j4JT9NhYzcAs-+ICUiz-Vd1zUeSZ6sfiKBEFDonydmPr6eZ31JmYfA+fJ8XYWl-gi-VwQdfSJvLcWAzpQd-3vf99rQA
TS Playground - An online editor for exploring TypeScript and JavaS...
The Playground lets you write TypeScript or JavaScript online in a safe and sharable way.