The function extract the form data and construct a Partial, the code works but i get this type error when using the function:
const loginForm = extractFormData<LoginForm>(formData);
Type 'LoginForm' does not satisfy the constrain 'StringOrNumber' , 'Index signature for type 'string' is missing in type 'LoginForm'
I dont understand why The type does not satisfy the constraint as LoginForm consist of strings.
I tried to make the login interface do string | number aswell and still the same error
interface LoginForm {
username: string | number;
password: string | number;
}
#CODE
interface LoginForm {
username: string;
password: string;
}
interface StringOrNumber {
[key: string]: string;
}
const extractFormData = <T extends StringOrNumber>(formData: FormData): T => {
//Use Partial<T> to construct the object incrementally
const data: Partial<T> = {};
formData.forEach((value, key) => {
let valueType: string;
let finalValue: string | number = value as string | number;
if (typeof value === "number") {
finalValue = value;
valueType = "number";
}
else if (typeof value === "string") {
valueType = "string";
}
else {
throw new Error(`Unexpected value type for key "${key}": Expected string or number, but got ${typeof value}`);
}
//data[key as keyof T] = finalValue;
data[key as keyof T] = finalValue as T[keyof T];
// Optionally log the key and its type
console.log(`${key}: ${finalValue} (${valueType})`);
for (const key in data) {
if (data[key] === undefined) {
throw new Error(`Missing value for required field: ${key}`);
}
}
});
// Validate that all required fields are present and correctly typed
for (const key in data) {
if (data[key] === undefined) {
throw new Error(`Missing value for required field: ${key}`);
}
}
// Return the data object cast to the specified type T
return data as T;
};
const loginForm = extractFormData<LoginForm>(formData);
A type that extends should be the same or wider than the extended one, but [key: string]
means any string key which is wider than LoginForm
's keys...
You could use a mapped conditional type to verify that your generic parameter is an object containing only string key and values:
type StringOrNumber<T extends object> = {
[K in keyof T as K extends string ? K : never]: T[K] extends string ? T[K]: never
}
const extractFormData = <T extends StringOrNumber<T>>(formData: FormData): T