چگونه میتوانم به صورت پویا ویژگیها را به یک شیء در تایپاسکریپت اختصاص دهم؟
اگر میخواستم به صورت برنامهنویسی یک ویژگی به یک شیء در جاوااسکریپت اختصاص دهم، این کار را به این صورت انجام میدادم:
var obj = {};
obj.prop = "value";
اما در تایپاسکریپت، این یک خطا ایجاد میکند:
ویژگی 'prop' در مقدار از نوع '{}' وجود ندارد
چگونه میتوانم هر ویژگی جدیدی را به یک شیء در تایپاسکریپت اختصاص دهم؟
پاسخ شماره ۱
امضاهای شاخص
ممکن است obj را به عنوان any مشخص کنیم، اما این کل هدف استفاده از تایپاسکریپت را از بین میبرد. obj={} به این معناست که obj یک Object است. علامتگذاری آن به عنوان any بیمعنی است. برای دستیابی به سازگاری مورد نظر، میتوان یک اینترفیس به صورت زیر تعریف کرد که از امضای اندیس استفاده میکند.
interface LooseObject {
[key: string]: any
}
var obj: LooseObject = {};
یا برای جمع و جور کردن آن:
var obj: {[k: string]: any} = {};
LooseObject میتواند فیلدهایی با کلید هر رشتهای و مقدار از نوع any بپذیرد.
obj.prop = "value";
obj.prop2 = 88;
ظرافت واقعی این راهحل این است که شما میتوانید فیلدهای نوعامن را در رابط گنجانید.
interface MyType {
typesafeProp1?: number,
requiredProp1: string,
[key: string]: any
}
var obj: MyType ;
obj = { requiredProp1: "foo"}; // valid
obj = {} // error. 'requiredProp1' is missing
obj.typesafeProp1 = "bar" // error. typesafeProp1 should be a number
obj.prop = "value";
obj.prop2 = 88;
نوع کمکی Record<Keys,Type>
بهروزرسانی (اوت ۲۰۲۰): @transang در کامنتها به نوع کاربردی Record<Keys,Type> اشاره کرد
Record<Keys,Type>یک نوع کمکی در تایپاسکریپت است. این یک جایگزین بسیار تمیزتر برای جفتهای کلید-مقدار است که در آن نام ویژگیها شناختهشده نیستند. قابل توجه است کهRecord<Keys,Type>یک نام مستعار برای{[k: Keys]: Type}است که در آنKeysوTypeجنریک هستند. به نظر من، این ارزش ذکر شدن در اینجا را دارد.
برای مقایسه،
var obj: {[k: string]: any} = {};
میشود
var obj: Record<string,any> = {}
اکنون میتوان MyType را با گسترش نوع Record تعریف کرد
interface MyType extends Record<string,any> {
typesafeProp1?: number,
requiredProp1: string,
}
در حالی که این پاسخ سؤال اصلی را میدهد، پاسخ اینجا توسط @GreeneCreations ممکن است دیدگاه دیگری درباره نحوه برخورد با مشکل ارائه دهد.
پاسخ شماره ۲
این راهحل زمانی مفید است که شیء شما نوع خاصی داشته باشد. مانند زمانی که شیء را از منبع دیگری به دست میآورید.
let user: User = new User();
(user as any).otherProperty = 'hello';
//user did not lose its type here.
پاسخ شماره ۳
یا همه یکجا:
var obj:any = {}
obj.prop = 5;
پاسخ شماره ۴
من معمولاً any را در سمت دیگر قرار میدهم یعنی var foo:IFoo=<any>{}; بنابراین چیزی شبیه به این هنوز ایمن از نظر نوع است:
interface IFoo{
bar:string;
baz:string;
boo:string;
}
// How I tend to intialize
var foo:IFoo = <any>{};
foo.bar = "asdf";
foo.baz = "boo";
foo.boo = "boo";
// the following is an error,
// so you haven't lost type safety
foo.bar = 123;
به طور متناوب میتوانید این ویژگیها را به عنوان اختیاری مشخص کنید:
interface IFoo{
bar?:string;
baz?:string;
boo?:string;
}
// Now your simple initialization works
var foo:IFoo = {};
بهصورت آنلاین امتحان کنید
پاسخ شماره ۵
من تعجب میکنم که هیچکدام از پاسخها به Object.assign اشاره نکردهاند، زیرا این همان تکنیکی است که هر زمان به «ترکیب» در جاوااسکریپت فکر میکنم، از آن استفاده میکنم.
و همانطور که انتظار میرود در TypeScript کار میکند:
interface IExisting {
userName: string
}
interface INewStuff {
email: string
}
const existingObject: IExisting = {
userName: "jsmith"
}
const objectWithAllProps: IExisting & INewStuff = Object.assign({}, existingObject, {
email: "[email "
})
console.log(objectWithAllProps.email); // [email
مزایا
- ایمنی نوع در سراسر برنامه زیرا شما اصلاً نیازی به استفاده از نوع
anyندارید - از نوع تجمیعی TypeScript استفاده میکند (همانطور که با
&هنگام اعلام نوعobjectWithAllPropsمشخص شده است)، که به وضوح بیان میکند که ما در حال ایجاد یک نوع جدید بهصورت لحظهای (یعنی پویا) هستیم
مواردی که باید به آنها توجه داشته باشید
Object.assign جنبههای منحصر به فرد خودش را دارد (که برای اکثر توسعهدهندگان با تجربه JS شناختهشده است) و باید هنگام نوشتن TypeScript در نظر گرفته شود.
- میتوان آن را به صورت قابل تغییر یا به صورت غیرقابل تغییر استفاده کرد (من روش غیرقابل تغییر را در بالا نشان دادهام، که به این معنی است که
existingObjectدستنخورده باقی میماند و بنابراین دارای خصوصیتemailنخواهد بود. برای اکثر برنامهنویسان سبک تابعی، این موضوع خوب است زیرا نتیجه تنها تغییر جدید است).
- میتوان آن را به صورت قابل تغییر یا به صورت غیرقابل تغییر استفاده کرد (من روش غیرقابل تغییر را در بالا نشان دادهام، که به این معنی است که
- تابع Object.assign زمانی بهترین عملکرد را دارد که شما اشیاء مسطحتری داشته باشید. اگر در حال ترکیب دو شیء تو در تو هستید که ویژگیهای nullable دارند، ممکن است مقادیر صحیح را با undefined بازنویسی کنید. اگر به ترتیب آرگومانهای Object.assign توجه کنید، همه چیز باید خوب باشد.
پاسخ شماره ۶
اگرچه کامپایلر اعتراض میکند، اما باید همچنان آن را به شکلی که شما میخواهید خروجی دهد. با این حال، این کار خواهد کرد.
const s = {};
s['prop'] = true;
پاسخ شماره ۷
یک گزینه دیگر برای انجام این کار این است که به ویژگی به عنوان یک مجموعه دسترسی پیدا کنید:
var obj = {};
obj['prop'] = "value";پاسخ شماره ۸
دیر ولی، پاسخ ساده
let prop = 'name';
let value = 'sampath';
this.obj = {
...this.obj,
[prop]: value
};
پاسخ شماره ۹
شما میتوانید بر اساس شی قدیمی، شیء جدیدی با استفاده از عملگر اسپرد ایجاد کنید
interface MyObject {
prop1: string;
}
const myObj: MyObject = {
prop1: 'foo',
}
const newObj = {
...myObj,
prop2: 'bar',
}
console.log(newObj.prop2); // 'bar'
تایپاسکریپت تمام فیلدهای شیء اصلی را استنباط خواهد کرد و ویاسکد تکمیل خودکار و غیره را انجام خواهد داد.
پاسخ شماره ۱۰
شما میتوانید از این استفاده کنید:
this.model = Object.assign(this.model, { newProp: 0 });
پاسخ شماره ۱۱
در اینجا یک نسخه ویژه از Object.assign وجود دارد که بهطور خودکار نوع متغیر را با هر تغییر در ویژگی تنظیم میکند. نیازی به متغیرهای اضافی، تأیید نوع، نوعهای صریح یا نسخههای کپی آبجکت نیست:
function assign<T, U>(target: T, source: U): asserts target is T & U {
Object.assign(target, source)
}
const obj = {};
assign(obj, { prop1: "foo" })
// const obj now has type { prop1: string; }
obj.prop1 // string
assign(obj, { prop2: 42 })
// const obj now has type { prop1: string; prop2: number; }
obj.prop2 // number
// const obj: { prop1: "foo", prop2: 42 }
توجه: این نمونه از توابع تایید TS 3.7 استفاده میکند. نوع بازگشتی assign برابر با void است، بر خلاف Object.assign.
پاسخ شماره ۱۲
مورد ۱:
var car = {type: "BMW", model: "i8", color: "white"};
car['owner'] = "ibrahim"; // You can add a property:
مورد ۲:
var car:any = {type: "BMW", model: "i8", color: "white"};
car.owner = "ibrahim"; // You can set a property: use any type
پاسخ شماره ۱۳
سادهترین کار، دنبال کردن خواهد بود
const obj = <any>{};
obj.prop1 = "value";
obj.prop2 = "another value"
