Typescript: Adakah peta jalan untuk mendukung Object.assign?

Dibuat pada 9 Jun 2015  ·  47Komentar  ·  Sumber: microsoft/TypeScript

di 1.6 atau 2.0?

Question

Komentar yang paling membantu

Maaf saya tidak mengerti. ES6 mendukung Object.assign jadi Babel mentranspilasinya ke polyfill untuk target ES5. Saya bingung mengapa TypeScript tidak melakukan hal yang sama, seperti halnya untuk fitur ES6 lainnya.

Semua 47 komentar

tidak yakin apa yang Anda cari. jika yang Anda maksud adalah pengetikan, itu sudah didefinisikan di lib.es6.d.ts sebagai

    /**
      * Copy the values of all of the enumerable own properties from one or more source objects to a 
      * target object. Returns the target object.
      * <strong i="6">@param</strong> target The target object to copy to.
      * <strong i="7">@param</strong> sources One or more source objects to copy properties from.
      */
    assign(target: any, ...sources: any[]): any;

Maksud Anda implementasinya, TypeScript tidak menyertakan pollyfill, Anda selalu dapat menyertakan pollyfill Anda, misalnya Mozilla memiliki pollyfill untuk itu.

Jika Anda bertanya tentang pengetikan pola mixin, itu adalah sesuatu yang selalu kami miliki di peta jalan untuk 2.0.

Terima kasih. Maksud saya menulis Object.assign(...) dalam TypeScript yang transparan ke es3 / es5 / es6. Jadi ini ada di peta jalan untuk 2.0.

: +1:

@unional Saya mungkin telah salah paham tentang sesuatu. Tapi menurut saya kesimpulan Anda tidak benar.

ES6 tetap mendukung Object.assign , jadi jika target Anda adalah ES6, Anda harus dapat menuliskannya di TypeScript.

Tetapi jika Anda mentranspilasi ke es5 dan di bawahnya, Anda masih memerlukan polyfill, karena es5 tidak memiliki Object.assign .

Sebagai solusi cepat, pertimbangkan polyfill dan pengetikan ini:

interface ObjectConstructor {
    assign(target: any, ...sources: any[]): any;
}

if (typeof Object.assign != 'function') {
  (function () {
    Object.assign = function (target) {
      'use strict';
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert undefined or null to object');
      }

      var output = Object(target);
      for (var index = 1; index < arguments.length; index++) {
        var source = arguments[index];
        if (source !== undefined && source !== null) {
          for (var nextKey in source) {
            if (source.hasOwnProperty(nextKey)) {
              output[nextKey] = source[nextKey];
            }
          }
        }
      }
      return output;
    };
  })();
}

Terima kasih telah memahami masalah ini. Sudah lama sekali. :) Ya, sekarang saya mengerti bahwa ini hanya membutuhkan polyfill untuk es5.

Terima kasih lagi!

Akankah kita mengkompilasi polyfill ini ketika target disetel ke es5? Maksud saya, karena target kompilasi diatur ke es5, maka ini harus dapat bekerja di lingkungan es5.

Akankah kita mengkompilasi polyfill ini ketika target disetel ke es5

Ya, sebagai ponyfill: mawar:: kuda:

Maaf saya tidak mengerti. ES6 mendukung Object.assign jadi Babel mentranspilasinya ke polyfill untuk target ES5. Saya bingung mengapa TypeScript tidak melakukan hal yang sama, seperti halnya untuk fitur ES6 lainnya.

@prashaantt TypeScript tidak menyediakan polyfill apa pun dan itu memang desainnya. Jika Anda ingin menggunakan Object.assign atau metode / primitif lain yang ditambahkan oleh standar yang lebih baru, Anda harus:

  • gunakan pustaka polyfill (seperti core-js ) dengan pengetikan yang sesuai
  • targetkan standar ketika fitur ditambahkan (mis. "target": "es6" dalam tsconfig.json )

@ devoto13 Terima kasih, core-js berfungsi dengan baik.

Saya hanya punya pertanyaan konyol. Setelah npm install ing dan typings install ing core-js saya mulai mendapatkan IntelliSense untuk metode polifill. Tetapi saya masih perlu benar-benar mengimpor metode tersebut di setiap modul tempat saya menggunakannya atau kode yang dikompilasi tidak akan menyertakan polyfill, bukan?

@prashaantt Sekali core-js/shim dibutuhkan oleh apapun, Object.assign akan tersedia secara global sejak saat itu dan seterusnya. Saya sarankan meletakkan import 'core-js/shim'; di bagian atas modul utama / titik masuk Anda.

Terima kasih @jesseschalken. Sebagai tindak lanjut, bukankah mengimpor seluruh shim akan membuat bundel saya membengkak? Atau akankah tsc atau ts-loader cukup pintar untuk hanya mengambil hal-hal yang benar-benar digunakan dalam kode saya?

@prashaantt Tergantung pada browser yang Anda targetkan. Anda sudah tahu Object.assign tidak didukung oleh browser yang Anda targetkan, siapa tahu apa lagi yang tidak? Anda membutuhkan seluruh shim dalam bundel Anda jika Anda menginginkan dukungan browser terluas.

Jika Anda hanya menginginkan polyfill seharga Object.assign , Anda dapat import 'core-js/modules/es6.object.assign'; , dan menambahkan lebih banyak hal saat Anda merasa membutuhkannya (lihat shim.js di core-js untuk daftarnya, juga dokumen). Webpack akan mengikuti grafik yang dibutuhkan dan hanya menyertakan modul yang diperlukan.

Jika Anda sudah menggunakan Babel, saya sarankan menggunakan import 'babel-polyfill'; daripada menggunakan core-js secara langsung. Ini termasuk core-js/shim tetapi juga regenerator-runtime untuk generator / async-await.

Terima kasih atas tipnya, meskipun kita harus memiliki dukungan generator penuh setiap saat sekarang - secara harfiah rintangan terakhir ke 2.0!

Maaf saya tidak mengerti. ES6 mendukung Object.assign sehingga Babel mentranspilasinya ke polyfill untuk target ES5. Saya bingung mengapa TypeScript tidak melakukan hal yang sama, seperti halnya untuk fitur ES6 lainnya.

@prashaantt Apa yang Anda maksud ketika Anda mengatakan bahwa Babel _transpiles_ Object.assign ? Itu hanyalah sebuah fungsi. Anda dapat menambahkan polyfill, ponyfill, atau menulisnya sendiri, dan Anda dapat menggunakannya di lingkungan apa pun - ES 3, 5.1, 6, dll.

@aluanhaddad Pemahaman saya tentang apa yang dilakukan babel adalah jika Anda menetapkan es5 sebagai target Anda dan menggunakan Object.assign , itu secara otomatis menyertakan polyfill untuk Object.assign , dan tidak jika Anda tidak menggunakannya. Alangkah baiknya jika skrip ketikan melakukan hal yang sama, seperti yang diklaim sebagai "superset of es2015", yang sebenarnya tidak benar jika tidak menyediakan fungsionalitas untuk mentranspilasi ke target yang lebih lama. (Saya bisa saja salah)

@ Devoto13 jika target Anda adalah es5, maka Anda setidaknya harus memberikan peringatan bahwa Object.assign tidak didukung di es5. Tidak masuk akal untuk membuatnya benar-benar valid dan tidak memberi tahu programmer bahwa Anda memerlukan polyfill acak.

@kyleholzinger apa yang Anda jelaskan (menargetkan ES5 berarti Object.assign tidak tersedia) sudah menjadi perilaku.

@kyleholinger Itu memang membuat kesalahan. Jika Anda membuat folder dengan dua file berikut:

// test.ts
let t = Object.assign({}, {});
// tsconfig.json
{ "target": "es5" }

Dan kemudian jalankan tsc di atasnya. Anda akan mendapatkan kesalahan berikut:

$ tsc
test.ts(1,16): error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.

Dalam proyek Anda, Anda mungkin menyertakan pengetikan untuk beberapa polyfill, tetapi tidak menyertakan implementasi polyfill, itulah mengapa gagal.

Saya mengerti bahwa itu adalah perilaku saat ini haha. Maksud saya adalah jika Anda menentukan target sebagai es5, alangkah baiknya jika skrip ketikan memberi Anda kesalahan yang berarti di luar "itu bukan pada konstruktor".

@kyleholzinger FWIW, TypeScript 2.1 sekarang mendukung objek istirahat / sebaran ES6 (ES7?) jadi saya pribadi menemukan alasan yang lebih rendah untuk repot-repot lagi tentang Object.assign . Itu dengan generator asli berarti saya tidak memerlukan polyfill di sebagian besar proyek saya.

Itu benar. Alangkah baiknya untuk tidak mengabaikan fitur bahasa. Akan luar biasa jika Object.assign tidak bergantung pada browser dan skrip memberi peringatan jika Anda tidak menggunakan polyfill.

Jika tsconfig Anda disetel dengan benar, TypeScript memperingatkan Anda tentang assign tidak tersedia untuk <ES6 dengan tidak memberi Anda opsi untuk melengkapi otomatis nama fungsi itu pada Object . Jika Anda terus menulis dengan tangan dengan susah payah, Anda akan melihat coretan merah. Jika Anda mengabaikannya, tsc akan menampilkan kesalahan di atas. Tetapi jika Anda dengan sengaja mengabaikannya juga, Anda berhak mendapatkan azab Anda. ;)

benar, satu-satunya poin saya adalah di spesifikasi es2015, jadi itu harus dalam naskah ketikan;)

Bagaimana cara menggunakan Object.assign pada node sambil menargetkan es5 ? Artinya, kode dijalankan di server dan bukan di browser. Apakah saya juga menggunakan polyfill dan bagaimana caranya?

@johnbendi
Itu tergantung pada versi node, artinya bergantung pada runtime seperti halnya dengan semua fungsionalitas polyfillable.

Berikut adalah cara melakukan pengujian jika runtime Anda mendukung Object.assign

$ Node 
> Object.assign({ to: 'world' }, { message: 'Hello there!' })
{ to: 'world', message: 'Hello there!' }

Jika cara di atas berhasil, yang perlu Anda lakukan adalah menyertakan "es2017.object" dalam properti "compilerOptions"."lib" pada tsconfig.json Anda.

Jika cara di atas gagal, tambahkan polyfill seperti ini, yang ditulis dalam TypeScript.

// polyfill-object-assign.ts

if (typeof Object.assign !== 'function') {
  Object.assign = function (target, ...args) {

    if (!target) {
      throw TypeError('Cannot convert undefined or null to object');
    }
    for (const source of args) {
      if (source) {
        Object.keys(source).forEach(key => target[key] = source[key]);
      }
    }
    return target;
  };
}

Dan impor dengan

import './polyfill-object-assign';

Dan juga buat perubahan yang sama pada tsconfig.json Anda seperti untuk kasus yang didukung runtime.

saya harap itu membantu

@aluanhaddad terima kasih banyak atas wawasannya. Node saya mendukung Object.assign berdasarkan percobaan yang Anda minta untuk saya jalankan. Tetapi bahkan setelah menambahkan "compilerOptions": { "lib": ["es2017.object"] } saya masih mendapatkan squiggles . Haruskah saya mengabaikannya atau ada sesuatu yang dapat saya lakukan untuk menghilangkannya.

@aluanhad sudahlah. Ini bekerja dengan baik sekarang.

@aluanhaddad Saya sebelumnya memiliki "compilerOptions": { "lib": ["es2017.object", "es6"] } ketika saya mendapatkan squiggles . Menghapus es6 tampaknya menyelesaikan tetapi menjalankan ulang skrip gulp saya lagi tiba-tiba menghasilkan serangkaian kesalahan baru.
Tsconfig.json saya:

{
    "compilerOptions": {
        "target": "es5",
        "module": "commonjs",
        "moduleResolution": "node",
        "lib": ["es2017.object"],
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true,
        "sourceMap": true,
        "inlineSources": true,
        //"noImplicitAny": true,
        "declaration": true,
        "noFallthroughCasesInSwitch": true,
        // "noImplicitReturns": true,
        "removeComments": true,
        "stripInternal": true,
        "outDir": "dist"
    },
    "files": ["src/main.ts"],
    "include": [
        "src/**/*.ts"
    ],
    "exclude": [
        "node_modules"
    ]
}

Contoh kesalahan baru saya:

error TS2318: Cannot find global type 'Array'.
error TS2318: Cannot find global type 'Boolean'.
error TS2318: Cannot find global type 'Function'.
error TS2318: Cannot find global type 'IArguments'.
error TS2318: Cannot find global type 'Number'.
error TS2318: Cannot find global type 'RegExp'.
error TS2318: Cannot find global type 'String'.
error TS2339: Property 'bind' does not exist on type '(message?: any, ...optionalParams: {}) => void'.
error TS2339: Property 'bind' does not exist on type '(message?: any, ...optionalParams: {}) => void'.
error TS2322: Type '{}' is not assignable to type
error TS2304: Cannot find name 'Promise'.

Jadi, apakah ada cara untuk menggunakan rekomendasi Anda dan masih mendapatkan skrip untuk dikompilasi dengan benar?

@johnbendi ya, tentu.

Penggunaan Saya hanya menyarankan untuk menambahkan entri spesifik "es2017.object" karena kekhususan permintaan Anda.
Saya yakin "lib": ["es6"] tidak lagi benar dan seharusnya "lib": ["es2015"] .
Coba "lib": ["es2015", es2017.object"] atau hanya "lib": ["es2017"] .

Saya rasa apa yang hilang adalah cara yang bersih untuk mengatakan "Saya memiliki polyfill es6 dan itu bukan skrip jenis bisnis Anda, anggap saja saya lakukan" :).

Karena, menyetel target: "es6" melakukan itu, tetapi mungkin juga dapat menghasilkan kode menggunakan fitur es6 non-polyfillable.

Membutuhkan core-j secara eksplisit pada dasarnya memaksa Anda untuk memiliki shim, Anda tidak dapat memiliki build shimmy dan non-shimmy karena TS akan mengeluh.

Menambahkan node_modules/typescript/lib/lib.es6.d.ts ke files di tsconfig.json memang begitu, tapi .. tidak terlihat begitu bersih ... (atau apakah saya melewatkan cara yang jelas untuk mencapainya?)

@himel cukup gunakan

{
  "compilerOptions": {
    "lib": [
      "es2015"
    ]
  }
}

Ini bekerja dengan sempurna - saya telah melakukannya selama berbulan-bulan.

Atau bagian apa pun yang Anda inginkan:

{
  "compilerOptions": {
    "lib": [
      "es2015.core",
      "es2016.array.include"
    ]
  }
}

Saya masih tidak tahu bagaimana melakukan ini. Ketika saya memiliki target: "es5" tsc akan selalu mengubah Object.assign menjadi beberapa panggilan ke polyfill. Menambahkan libs tidak mengubah apa pun bagi saya.

Dalam kasus saya, saya ingin fungsi panah diubah ke fungsi normal, tetapi biarkan panggilan statis seperti Object.assign dan Array.includes tidak tersentuh.

tsc harus memiliki sebuah bendera untuk memberitahukannya untuk hanya mentranspilasi fitur sintaks dan bukan fitur polyfill seperti metode statis Object , Array dll.

Ketika saya memiliki target: "es5" tsc akan selalu mengubah Object.assign menjadi beberapa panggilan ke polyfill.

@danez TypeScript tidak akan mengubah panggilan ke Object.assign . Sepertinya Anda menjalankan kode melalui Babel?

@RyanCavanaugh Memang. Babel tidak terlibat dalam proses tersebut.
Apa yang dilakukannya pada dasarnya mengubah ini:

var a = Object.assign({}, {});

ke dalam ini

var __assign = (this && this.__assign) || Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};
var a = _assign({}, {});

@danez Dapatkah Anda memposting laporan aktual? Kompilator tidak mengeluarkan kode itu

Saya tidak punya repo, tapi ini tsconfignya:

{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "module": "ES2015",
    "target": "es5",
    "outDir": "js/lib/es"
  },
  "include": [
    "js/**/*.ts",
  ],
  "exclude": [
    "**/__tests__/**/*.ts"
  ]
}

dan kemudian saya cukup menelepon tsc

@danez Saya khawatir Anda harus memposting repro yang sebenarnya.

C:\Throwaway\oat>type a.ts
var a = Object.assign({}, {});

C:\Throwaway\oat>type tsconfig.json
{
  "compilerOptions": {
    "noImplicitAny": true,
    "strictNullChecks": true,
    "module": "ES2015",
    "target": "es5",
    "outDir": "js/lib/es"
  },
  "include": [
    "*.ts",
  ]
}
C:\Throwaway\oat>tsc
a.ts(1,16): error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.

C:\Throwaway\oat>type js\lib\es\a.js
var a = Object.assign({}, {});

@unional karena berfungsi dengan baik . Kompilator memiliki pembantu untuk menyediakan dukungan sintaksis, tetapi tidak _ever_ fungsi penulisan ulang di global. @danez pembantu itu tidak pernah dapat diakses oleh kode TypeScript.

const foo = { foo: 'bar' };
const bar = { ...foo };

akan memancarkan:

var __assign = (this && this.__assign) || Object.assign || function(t) {
    for (var s, i = 1, n = arguments.length; i < n; i++) {
        s = arguments[i];
        for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
            t[p] = s[p];
    }
    return t;
};
var foo = { foo: 'bar' };
var bar = __assign({}, foo);

Saya tidak berpikir Anda dapat memberikan contoh di mana Object.assign() ditulis ulang menjadi __assign , itu hanya digunakan dalam dukungan sintaksis penyebaran objek.

@kitsonk Ya saya menggunakan penyebaran objek, Anda benar. Jadi alangkah baiknya jika penyebaran objek hanya akan diubah menjadi Object.assign

@danez itu adalah ketika Anda menargetkan sesuatu yang mendukung Object.assign() (mis. targetnya adalah es2015 +).

Misalnya, ini:

const foo = { foo: 'bar' };
const bar = { ...foo };

Akan menghasilkan:

const foo = { foo: 'bar' };
const bar = Object.assign({}, foo);

@kitsonk Ya saya tahu, tapi saya menargetkan es5 _syntax_ dengan semua global ES2017 + yang di-polyfill oleh core-js. Jadi yang saya maksud adalah apa yang akan menyenangkan adalah mode yang mengeluarkan sintaks es5 tetapi mengasumsikan semua bawaan tersedia. Mirip dengan apa yang dilakukan babel dengan opsi useBuiltins : https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx#usebuiltins

Secara umum, kami tidak berusaha keras untuk memberikan dukungan khusus kepada target waktu proses "campuran", tetapi ada opsi lain yang tersedia.

Anda dapat menyuntikkan __assign ke dalam cakupan global (bersama dengan pembantu lainnya, misalnya __extends ) dan menjalankan dengan --noEmitHelpers .

Ya saya tahu, tapi saya menargetkan es5 _syntax_

Saya merasa ini adalah masalah utama dengan tidak adanya fitur shimming seperti Object.assign . Harus mengambil sikap dengan satu atau lain cara-- Anda tidak dapat mengganti penggunaannya dengan __assign saat menggunakan spread tetapi tidak ketika Anda memanggilnya secara langsung, itu membingungkan sekali

Anda tidak dapat mengganti penggunaannya dengan __assign saat menggunakan spread tetapi tidak saat Anda memanggilnya secara langsung, ini sangat membingungkan

Saya dapat memahami Anda merasa itu membingungkan, tetapi tidak jika Anda menyimpan mantra, TypeScript menyediakan _syntatical rewrites_ bukan _functional polyfills_. TypeScript sepenuhnya konsisten dalam cara perilakunya, dan ia berpendapat tentang apa yang dilakukannya, dan 99% dari waktu itu tidak berdampak pada pengguna akhir.

Seperti yang dikatakan @RyanCavanaugh , dimungkinkan untuk memanfaatkan satu set polyfill, ditambah tslib , dengan --noEmitHelpers ditambah skrip global yang mengatakan:

__assign = Object.assign;

Tapi itu benar-benar TypeScript "putaran bonus" dan dapat diperdebatkan bahwa itu akan memberikan peningkatan kinerja terukur dunia nyata.

Apakah halaman ini membantu?
0 / 5 - 0 peringkat