admin管理员组文章数量:1398111
So I have this function...
updateField ( tenantId: string, fieldname: string, value: string | number | boolean | Array<SubTenant> | undefined) {
const tenantPartial = {} as Partial<Tenant>;
if(fieldname != "id"){
tenantPartial[fieldname as keyof Tenant] = value as any;
}
this.buildingService.updateTenantField(this.buildingId, tenantId, tenantPartial)
}
that uses this interface (simplified to what matters for the question)
export interface Tenant{
name: string;
readonly id: string
}
and fails with this error :
Cannot assign to 'id' because it is a read-only property.
(parameter) fieldname: string
As you can see, I tried eliminating the possibility that 'id' is used as a keyof Tenant, but that doesn't clear the error. How do I clear this error?
So I have this function...
updateField ( tenantId: string, fieldname: string, value: string | number | boolean | Array<SubTenant> | undefined) {
const tenantPartial = {} as Partial<Tenant>;
if(fieldname != "id"){
tenantPartial[fieldname as keyof Tenant] = value as any;
}
this.buildingService.updateTenantField(this.buildingId, tenantId, tenantPartial)
}
that uses this interface (simplified to what matters for the question)
export interface Tenant{
name: string;
readonly id: string
}
and fails with this error :
Cannot assign to 'id' because it is a read-only property.
(parameter) fieldname: string
As you can see, I tried eliminating the possibility that 'id' is used as a keyof Tenant, but that doesn't clear the error. How do I clear this error?
Share Improve this question asked Mar 25 at 20:56 Jon ThompsonJon Thompson 4464 silver badges19 bronze badges2 Answers
Reset to default 1The problem is that your fieldName
is declared as a string
, so != 'id'
does not narrow it - Exclude<string, 'id'>
is still string
, TypeScript does not support negated types (see Type for "every possible string value except ...").
You can either change your parameter to keyof Tenant
, which is basically 'id' | 'name'
, then that union will be narrows to just 'name'
by your if
statement:
updateField (fieldname: keyof Tenant, value) {
const tenantPartial = {} as Partial<Tenant>;
if (fieldname != "id") {
tenantPartial[fieldname] = value;
}
}
or if you want to keep the type assertion, you need express the elimination of 'id'
yourself:
updateField (fieldname: string, value) {
const tenantPartial = {} as Partial<Tenant>;
if (fieldname != "id") {
tenantPartial[fieldname as Exclude<keyof Tenant, 'id'>] = value;
}
}
I think your whole approach of accepting any field name and value isn't in spirit of TS, actually you'd like to accept only writable key/value pair here most probably, in that case you should accept only writeable keys with corresponding values types. This will also give you a helpful intellisense:
Playground
interface Tenant{
name: string;
employeeCount: number,
readonly id: string
}
type Equal<X, Y> = (<T>() => T extends X ? 1 : 2) extends <T>() => T extends Y ? 1 : 2 ? true : false;
type GetReadonlyKeys<
T,
U extends Readonly<T> = Readonly<T>,
K extends keyof T = keyof T
> = K extends keyof T ? Equal<Pick<T, K>, Pick<U, K>> extends true ? K : never : never
type GetWriteOnlyKeys<T> = Exclude<keyof T, GetReadonlyKeys<T>>;
function updateField<K extends GetWriteOnlyKeys<T>, T extends Tenant>(...[fieldname, value]: K extends any ? [K, T[K]] : never) {
const tenantPartial = {} as Partial<T>;
tenantPartial[fieldname] = value
}
updateField("name", 'Tenant');
updateField("employeeCount", 1);
updateField("employeeCount", 'string'); // wrong value
updateField("id", 'string'); // not writable
updateField("name2", 'string'); // non existing prop
本文标签:
版权声明:本文标题:typescript - using "as keyof interface" to convert string to key results in error if there is a readonly in th 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744168938a2593684.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论