2015-04-13 18 views
5

Mục tiêusở hữu giao diện typescript để chuỗi

Tôi có một nguyên cảo giao diện:

interface IInterface{ 
    id: number; 
    name: string; 
} 

Tôi có một số phương pháp mà mất trong mục tên của một tài sản (string).

Ex:

var methodX = (property: string, object: any) => { 
    // use object[property] 
}; 

Vấn đề của tôi là khi tôi gọi methodX, tôi phải viết tên thuộc tính trong chuỗi.

Ex:methodX("name", objectX);nơi objectX thực hiện IInterface

Nhưng đây là BAD: Nếu tôi đổi tên một tài sản (giả sử tôi muốn đổi tên name-lastname) i sẽ phải cập nhật bằng tay tất cả của tôi mã.

Và tôi không muốn sự phụ thuộc này.

Vì giao diện bản ghi không có triển khai JS, tôi không thấy cách tôi không thể sử dụng chuỗi.

Tôi muốn có một cái gì đó như: methodX(IInterface.name.propertytoString(), objectX);

Tôi khá mới để JS, bạn sẽ thấy một sự thay thế?

(Tùy chọn) Chi tiết khác: Tại sao tôi cần chuyển thuộc tính làm tham số và tại sao tôi không sử dụng phương pháp chung?

tôi sử dụng phương pháp liên kết dữ liệu:

linkData = <TA, TB>(
    inputList: TA[], 
    inputId: string, 
    inputPlace: string, 
    outputList: TB[], 
    outputId: string) => { 

    var mapDestinationItemId: any = {}; 
    var i: number; 
    for (i = 0; i < outputList.length; ++i) { 
     mapDestinationItemId[outputList[i][outputId]] = outputList[i]; 
    } 

    var itemDestination, itemSource; 
    for (i = 0; i < inputList.length; ++i) { 
     itemDestination = inputList[i]; 
     itemSource = mapDestinationItemId[itemDestination[inputId]]; 
     if (itemSource) { 
      itemDestination[inputPlace] = itemSource; 
     } 
    } 
}; 

Nhưng TA và TB có thể có rất nhiều id khác nhau. Vì vậy, tôi không thấy làm thế nào để làm cho nó chung chung hơn.

Trả lời

6

basarat câu trả lời là một ý tưởng hay, nhưng nó không hoạt động với giao diện.

Bạn không thể viết methodX(interfacePropertyToString(()=>interfaceX.porpertyname), objectX)interfaceX không phải là một đối tượng.

Giao diện là trừu tượng và chúng chỉ được sử dụng cho TypeScript, chúng không tồn tại trong Javascript.

Nhưng nhờ câu trả lời của mình, tôi đã tìm ra giải pháp: sử dụng thông số trong phương pháp.

Cuối cùng ta có:

interfacePropertyToString = (property: (object: any) => void) => { 
     var chaine = property.toString(); 
     var arr = chaine.match(/[\s\S]*{[\s\S]*\.([^\.; ]*)[ ;\n]*}/); 
     return arr[1]; 
    }; 

Chúng ta phải sử dụng [\s\S] để có thể phù hợp trên multilines vì ​​nguyên cảo chuyển đổi (object: Interface) => {object.code;} đến một chức năng có nhiều dòng.

Bây giờ bạn có thể sử dụng nó như bạn muốn:

 interfacePropertyToString((o: Interface) => { o.interfaceProperty}); 
     interfacePropertyToString(function (o: Interface ) { o.interfaceProperty}); 
+0

Great câu trả lời! Bạn có thể giải thích một chút về cách thức giao dịch của TypeScript với các giao diện do người dùng định nghĩa và nó biên dịch chúng thành gì? Bởi vì tôi không tìm thấy nhiều về điều này. Cảm ơn! –

+0

Ngoài ra, bạn có thể nghĩ ra cách nào để trích xuất tất cả các thuộc tính của giao diện theo cách này không? Cảm ơn! –

+0

@ radu-matei Giao diện TypeScript không chuyển thành Javascript. Nó đơn giản không tồn tại trong Javascript. – Machtyn

2

Bạn có thể viết một hàm để phân tích cơ thể của một chức năng để tìm tên ví dụ:

methodX(getName(()=>something.name), objectX) 

đâu getName sẽ làm một toString trên cơ thể chức năng để có được một chuỗi các hình thức "function(){return something.name}" và sau đó phân tích cú pháp nó để có được "name".

Lưu ý: tuy nhiên điều này có xu hướng phá vỡ tùy thuộc vào cách bạn giảm thiểu nó.

0

vấn đề Hơi liên quan - làm thế nào để nhận/đặt một giá trị cho một con đường bất động sản. Tôi đã viết hai lớp cho rằng:

export class PropertyPath { 
    static paths = new Map<string, PropertyPath>() 

    static get<T, P>(lambda: (prop:T) => P) : PropertyPath { 
     const funcBody = lambda.toString(); 
     var ret : PropertyPath = this.paths[funcBody]; 
     if (!ret) { 
      const matches = funcBody.match(/(?:return[\s]+)(?:\w+\.)((?:\.?\w+)+)/); //first prop ignores 
      var path = matches[1]; 
      ret = new PropertyPath(path.split(".")); 
      this.paths[funcBody] = ret; 
     } 
     return ret; 
    }; 

    path : Array<string> 

    constructor(path : Array<string>) { 
     this.path = path 
    } 

    getValue(context : any) { 
     const me = this; 
     var v : any; 
     return this.path.reduce((previous, current, i, path) => { 
      try { 
       return previous[current]; 
      } 
      catch (e) { 
       throw { 
        message : `Error getting value by path. Path: '${path.join(".")}'. Token: '${current}'(${i})`, 
        innerException: e 
       }; 
      } 
     }, context) 
    } 

    setValue(context : any, value : any) { 
     const me = this; 
     var v : any; 
     this.path.reduce((previous, current, i, path) => { 
      try { 
       if (i == path.length - 1) { 
        previous[current] = value 
       } 
       return previous[current]; 
      } 
      catch (e) { 
       throw { 
        message : `Error setting value by path. Path: '${path.join(".")}'. Token: '${current}'(${i}). Value: ${value}`, 
        innerException: e 
       }; 
      } 
     }, context) 
    } 

} 

Ví dụ về sử dụng:

var p = PropertyPath.get((data:Data) => data.person.middleName) 
var v = p.getValue(data) 
p.setValue(data, newValue) 

Một số đường trên nó:

export class PropertyPathContexted { 

    static get<T, P>(obj : T, lambda: (prop:T) => P) : PropertyPathContexted { 
     return new PropertyPathContexted(obj, PropertyPath.get(lambda)); 
    }; 

    context: any 
    propertyPath: PropertyPath 

    constructor(context: any, propertyPath: PropertyPath) { 
     this.context = context 
     this.propertyPath = propertyPath 
    } 

    getValue =() => this.propertyPath.getValue(this.context) 

    setValue = (value : any) => {this.propertyPath.setValue(this.context, value) } 

} 

Và sử dụng:

var p = PropertyPathContexted.get(data,() => data.person.middleName) 
var v = p.getValue() 
p.setValue("lala") 

tôi tìm ra mới nhất khá thuận tiện trong hai chiều databinding trong Phản ứng:

var valueLink = function<T, P>(context: T, lambda: (prop:T) => P) { 
    var p = PropertyPathContexted.get(context, lambda); 
    return { 
     value: p.getValue(), 
     requestChange: (newValue) => { 
      p.setValue(newValue); 
     } 
    } 
}; 

render() { 
    var data = getSomeData() 
    //... 
    return (
     //... 
     <input name='person.surnames' placeholder='Surnames' valueLink={valueLink(data,() => data.person.surnames)}/> 
     //... 
    ) 
} 
Các vấn đề liên quan