TS泛型进阶

发表于 2年以前  | 总阅读数:472 次

拿下泛型,TS 还有什么难的吗?

大家好,我是沐华,本文将剖析 TS 开发中常见工具类型的源码实现及使用方式,并且搭配与内容结合的练习,方便大家更好的理解和掌握。本文目标:

  • 更加深入的理解和掌握泛型
  • 更加熟练这些内置工具类型在项目中的运用

Exclude

Exclude<T, U>:作用简单说就是把 T 里面的 U 去掉,再返回 T 里还剩下的。TU 必须是同种类型(具体类型/字面量类型)。如下

type T1 = Exclude<string | number, string>;
// type T1  = number; 

// 上面这个肯定一看就懂,那下面这样呢

type T2 = Exclude<'a' | 'b' | 'c', 'b' | 'd'>;
// type T2  = 'a' | 'c';

怎么就剩个 a | c 了?这怎么执行的?

先看一张图

三元表达式大家都知道,不是返回 a 就是返回 b,这么算的话,这个 some 的类型应该是 b 才对呀,可这个结果是 a | b 又是怎么回事呢,这都是由于 TS 中的拆分或者说叫分发机制导致的

简单说就是联合类型并且是裸类型就会产生分发,分发就会把联合类型中的每一个类型单独拿去判断,最后返回结果组成的联合类型a | b 就是这么来的,这个特性在本文后面会提到多次所以铺垫一下,这也是为什么反 Exclude 放在开头的原因

结合 Exclude 的实现和例子来理解下


// 源码定义
type Exclude<T, U> = T extends U ? never : T;

// 例子
type T2 = Exclude<'a' | 'b' | 'c', 'b' | 'd'>;
// type T2  = 'a' | 'c';

上面例子中的执行逻辑:

  • 由于分发会把联合类型中的每一个类型单独拿去判断的原因,会先把 T ,也就是前面 a | b | c 给拆分再单独放入 T extends U ? never : T 判断
  • 第一次判断 a(T就是a)U 就是 b | dT 并没有继承自 U,判断为假,返回 T 也就是 a
  • 第二次判断放入 b 判断为真,返回 neverts 中的 never 我们知道就是不存在值的意思,连 undefined 都没有,所以 never 会被忽略,不会产生任何效果
  • 第三次判断放入 c,判断为假,和 a 同理
  • 最后将每一个单独判断的结果组成联合类型返回never 会忽略,所以就剩下 a | c

总之就是:如果 T extends U 满足分发的条件,就会把所有单个类型依次放入判断,最后返回记录的结果组合的联合类型

Extract

Extract<T, U>:作用是取出 T 里面的 U ,返回。作用和 Exclude 刚好相反,传参也是一样的

看例子理解 Extract

type T1 = Extract<'a' | 'b' | 'c', 'a' | 'd'>;
// type T1  = 'a';

// 源码定义
type Extract<T, U> = T extends U ? T : never

Exclude 源码对比也只是三元表达式返回的 never : T 对调了一下,执行原理也是一样一样儿的,就不重复了

Omit

Omit<T, K>:作用是把 T(对象类型) 里边的 K 去掉,返回 T 里还剩下的

Omit 的作用和 Exclude 是一样的,都能做类型过滤并得到新类型。

不同的是 Exclude 主要是处理联合类型,且会触发分发,而 Omit 主要是处理对象类型,所以自然的这俩参数也不一样。

用法如下

// 这种场景 type 和 interface 是一样的,后面就不重复说明了
type User = {
    name: string
    age: number
}
type T1 = Omit<User, 'age'>
// type T1 = { name: string }

源码定义

// keyof any 就是 string | number | symbol
type Omit<T, K extends keyof any> = { [P in Exclude<keyof T, K>]: T[P]; }
  • 首先第一个参数 T 要传对象类型, typeinterface 都可以
  • 第二个参数 K 限制了类型只能是 string | number | symbol,这一点跟 js 里的对象是一个意思,对象类型的属性名只支持这三种类型
  • in 是映射类型,用来映射遍历枚举类型。大白话就是循环、循环语法,需要配合联合类型来对类型进行遍历。in 的右边是可遍历的枚举类型,左边是遍历出来的每一项
  • Exclude 去除掉传入的属性后,再遍历剩下的属性,生成新的类型返回

示例解析:

type User = {
    name: string
    age: number
    gender: string
}
type Omit<T, K extends keyof any> = { [P in Exclude<keyof T, K>]: T[P]; }
type T1 = Omit<User, 'age'>
// type T1 = { name: string, gender: string }

我们调用 Omit 传入的参数是正确的,所以就分析一下后面的执行逻辑:

  • Exclude<keyof T, K> 等于 Exclude<'name'|'age'|'gender', 'age'>,返回的结果就是 'name'|'gender
  • 然后遍历 'name'|'gender',第一次循环 P 就是 name,返回 T[P] 就是 User['name']
  • 第二次循环 P 就是 gender,返回 T[P] 就是 User['gender'],然后循环结束
  • 结果就是 { name: string, gender: string }

Pick

Pick<T, K> :作用是取出 T(对象类型) 里边儿的 K,返回。

好像和 Omit 刚好相反,Omit 是不要 KPick 是只要 K

传参方式和 Omit 是一样的,就不赘述了,用法示例:

type User = {
    name: string
    age: number
    gender: string
}
type T1 = Pick<User, 'name' | 'gender'>
// type T1 = { name: string, gender: string }

源码定义

type Pick<T, K extends keyof T> = { [P in K]: T[P]; }
  • 可以看到等号左边做了泛型约束,限制了第二个参数 K 必须是第一个参数 T 里的属性。
  • 如果第二个参数传入联合类型,会触发分发,以此来确保准确性,联合类型中的每一个单独类型都必须是第一个对象类型中的属性(不限制的话右边就要出错了)
  • 参数都正确之后,等号右边的逻辑其实就是和 Omit 一模一样的了,直接遍历 K,取出返回就完事儿了

练习一

请利用本文上述内容完成:基于如下类型,实现一个去掉了 gender 的新类型,实现方法越多越好

type User = {
    name: string
    age: number
    gender: string
}

这个?

type T1 = { name: string, age: number }

???

我写了几个,欢迎补充:

type T1 = Omit<User, 'gender'>
type T2 = Pick<User, 'name' | 'age'>
type T3 = Pick<User, Exclude<keyof User, 'gender'>>
type T4 = { [P in 'name' | 'age'] : User[P] }
type T5 = { [P in Exclude<keyof User, 'gender'>] : User[P] }

Record

Record<K, T>:作用是自定义一个对象。K 为对象的 keykey 的类型,Tvaluevalue 的类型。

你有没有这样用过 ↓

const obj:any = {}

反正我有,其实用 Record 定义对象,在工作中还是很好用的,而且非常灵活,不同的对象定义上也会有一点区别,如下

空对象

// never,会限制为空对象
// any 指的是 string | number | symbol 这几个类型都行
type T1 = Record<any, never>
let obj1:T1 = {}  // ok
// let obj1:T1 = {a:1} 这样不行,只能是空对象

任意对象

// 任意对象,unknown 或 {} 表示对象内容不限,空对象也行
type T1 = Record<any, unknown>
// 或
type T1 = Record<any, {}>
let obj2:T1 = {}  // ok
let obj3:T1 = {a:1}  // ok

自定义对象 key

type keys = 'name' | 'age'
type T1 = Record<keys, string>
let obj1:T1 = {
    name: '沐华',
    age: '18'
    // age: 18  报错,第二个参数 string 表示 value 值都只能是 string 类型
}

// 如果需要 value 是任意类型,下面两个都行
type T2 = Record<keys, unknown>
type T3 = Record<keys, {}>

自定义对象 value

type keys = 'a' | 'b'
// type 或 interface 都一样
type values<T> = {
    name?: T,
    age?: T,
    gender?: string
}

// 自定义 value 类型
type T1 = Record<keys, values<number | string>>
let obj:T1 = {
    a: { name: '沐华' },
    b: { age: 18 }
}

// 固定 value 值
type T2 = Record<keys, 111>
let obj1:T2 = {
    a: 111,
    b: 111
}

源码定义

type Record<K extends any, T> = { [P in K]: T; }

左边限制了第一个参数 K 只能是 string | number | symbol 类型,可以是联合类型,因为右边遍历 K 了,然后遍历出来的每个属性的值,直接赋值为传入的第二个参数

Partial

Partial<T>:作用生成一个将 T(对象类型) 里所有属性都变成可选的之后的新类型

示例如下:

type User = {
    name: string
    age: number
}
type T1 = Partial<User>
// 简单说 T1 和 T2 是一模一样的
type T2 = {
    name?: string
    age?: number
}

源码定义

type Partial<T> = { [P in keyof T]?: T[P]; }

这下看源码定义的是不是特别简单,就是循环传进来的对象类型,给每个属性加个 ? 变成可选属生

Required

Required<T>:作用和 Partial<T> 刚好相反,Partial 是返回所有属性都是非必填的对象类型,而 Required 则是返回所有属性都是必填项的对象类型。参数 T 也是一个对象类型。

示例:

type User = {
    name?: string
    age?: number
}
type T1 = Required<User>
// 简单说 T1 和 T2 是一模一样的
type T2 = {
    name: string
    age: number
}

源码定义

type Required<T> = { [P in keyof T]-?: T[P]; }

Partial 的源码定义相比基本一样的,只是这里多了个减号 -,没错,就是减去的意思,-? 就是去掉 ?,然后就变成必填项了,这样解释是不是很好理解

Readonly

Readonly<T> :作用是返回一个所有属性都是只读不可修改的对象类型,与 PartialRequired 是非常相似的。参数 T 也是一个对象类型。

示例:

type User = {
    name: string
    age?: number
}
type T1 = Readonly<User>
// 简单说 T1 和 T2 是一模一样的
type T2 = {
    readonly name: string
    readonly age?: number
}
type Readonly<T> = { readonly [P in keyof T]: T[P]; }

怎么样?看到这是不是越发觉得源码的类型定义越看越简单了

我:那是不是说把所有只读类型,全都变成非只读就只需要 -readonly 就行了?

你:是的,说得很对,就是这样的

练习二

从上面几个工具类型的源码定义中我们可以发现,都只是简单的一层遍历,就好像 js 中的浅拷贝,比如有下面这样一个对象

type User = {
    name: string
    age: number
    children: {
        boy: number
        girl: number
    }
}

要把这样一个对象所有属性都改成可选属性,用 Partial 就行不通了,它只能改变第一层,children 里的所有属性都改不了,所以请写一个可以实现的类型,功能类似深拷贝的意思

先稍微想想再往下看答案哟

写出来一个的话,PartialRequiredReadonly 的 “深拷贝” 类型是不是就都有了呢

想一下

// Partial 源码定义
type Partial<T> = { [P in keyof T]?: T[P]; }

// 递归 Partial
type DeepPartial<T> = T extends object ? { [P in keyof T]?: DeepPartial<T[P]> }:T;

外层再加了一个三元表达式,如果不是对象类型直接返回,如果是就遍历;然后属性值改成递归调用就可以了

// 递归 Required
type DeepRequired<T> = T extends object ? { [P in keyof T]-?: DeepRequired<T[P]> }:T;

// 递归 Readonly
type DeepReadonly<T> = T extends object ? { readonly [P in keyof T]: DeepReadonly<T[P]> }:T;

NonNullable

NonNullable<T>:作用是去掉 T 中的 nullundefinedT 为字面量/具体类型的联合类型,如果是对象类型是没有效果的。如下

type T1 = NonNullable<string | number | undefined>;
// type T1 = string | number

type T2 = NonNullable<string[] | null | undefined>;    
// type T2 = string[]

type T3 = {
    name: string
    age: undefined
}
type T4 = NonNullable<T3> // 对象是不行的

源码定义

// 4.8版本之前的版本
type NonNullable<T> = T extends null | undefined ? never : T;
// 4.8
type NonNullable<T> = T & {}

TS 4.8版本 之前的就是用一个三元表达式来过滤 null | undefined。而在 4.8 版本直接就是 T & {},这是什么原理呢?其实是因为这个版本对 --strictNullChecks 做了增加,这主要体现还是在联合类型和交叉类型上,为什么这么说?

js 中都知道万物皆对象,原型链的最终点的正常对象就是 Object 了(null 算不正常的),数据类型都是在原型链中继承于 Object 派生出来的。

ts 中也一样,由于 {} 是一个空对象,所以除了 nullundefined 之外的基础类型都可以视作继承于 {} 派生出来的。或者说如果一个值不是 nullundefined 就等于 这个值 & {} 的结果,如下

type T1 = 'a' & {};  // 'a'
type T2 = number & {};  // number
type T3 = object & {};  // object
type T4 = { a: string } & {};  // { a: string }
type T5 = null & {};  // never
type T6 = undefined & {};  // never

如果 T & {} 中的 T 不是 null/undefined 就可以认为它肯定符合 {} 类型,就可以把 {} 从交叉类型中去掉了,如果是,则会被判为 never,而 never 是会被忽略的(上面 Exclude 源码定义里有提到),所以在结果里自然就排除掉了 nullundefined

还有如果 T & {} 中的 T 是联合类型,是会触发分发的,这个就不再解释了

练习三

请实现一个能去掉对象类型中 nullundefined 的类型

// 需要把如下类型变成 { name: string }
type User = {
    name: string
    age: null,
    gender: undefined
}

// 实现如下
type ObjNonNullable<T> = { [P in keyof T as T[P] extends null | undefined ? never : P]: T[P] };

type T1 = ObjNonNullable<User>
// type T1 = { name: string }

这里出现了一个本文第一次出现的关键字 as,我们知道它可以用来断言,在 ts 4.1 版本可以在映射类型里用 as 实现键名重新映射,达到过滤或者修改属性名的目的,如果指定的类型解析为 never 时,会被忽略不会生成这个属性

如上只能过滤对象第一层的 nullundefined

如何更进一步改成可以递归的呢?

type User = {
    name: string
    age: undefined,
    children: {
        boy: number
        girl: number
        neutral: null
    }
}
// 递归处理对象类型的 DeepNonNullable
type DeepNonNullable<T> = T extends object ? { [P in keyof T as T[P] extends null | undefined ? never : P]: DeepNonNullable<T[P]> } : T;

type T1 = DeepNonNullable<User>
// type T1 = {
//    name: string;
//    children: {
//        boy: number;
//        girl: number;
//    };
//}

Awaited

Awaited<T>:作用是获取 async/await 函数或 promisethen() 方法的返回值的类型。而且自带递归效果,如果是这样嵌套的异步方法,也能拿到最终的返回值类型

示例:

// Promise
type T1 = Awaited<Promise<string>>;
// type T1 = string

// 嵌套 Promise,会递归
type T2 = Awaited<Promise<Promise<number>>>;
// type T2 = number

// 联合类型,会触发分发
type T3 = Awaited<boolean | Promise<number>>;
// type T3 = number | boolean

来看下源码定义,看下到底是怎么执行的,是怎么拿到结果的呢?

// 源码定义
type Awaited<T> = T extends null | undefined
 ? T
 : T extends object & { then(onfulfilled: infer F): any }
  ? F extends (value: infer V, ...args: any) => any
   ? Awaited<V>
   : never
  : T

泛型条件有点多,就换了下行,方便看

  • 如果 Tnullundefined 就直接返回 T

  • 如果 T 是对象类型,并且里面有 then 方法,就用 infer 类型推断出 then 方法的第一个参数onfulfilled 的类型赋值给 Fonfulfilled 其实就是我们熟悉的 resolve。所以这里可以看出或者准确的说,Awaited 拿的不是 then() 的返回值类型,而是 resolve() 的返回值类型

  • 传入 V 递归调用

  • 既然 F 是回调函数 resolve ,就推断出该函数第一个参数类型赋值给 Vresolve 的参数自然就是返回值

  • F 不是函数就返回 never

  • 如果 T 不是对象类型 或者 是对象但没有 then 方法,返回 T ,就是最后一行的 T

Parameters

Parameters<T>:作用是获取函数所有参数的类型集合,返回的是元组。T 自然就是函数了

使用示例:

declare function f1(arg: { a: number; b: string }): void;

// 没有参数的函数
type T1 = Parameters<() => string>;
// type T1 = []

// 一个参数的函数
type T2 = Parameters<(s: string) => void>;
// type T2 = [s: string]

// 泛型参数的函数
type T3 = Parameters<<T>(arg: T) => T>;
// type T3 = [arg: unknown]

// typeof f1 结果为 (arg: { a: number; b: string }) => void
type T4 = Parameters<typeof f1>;
// type T4 = [arg: {
//     a: number;
//     b: string;
// }]

// any 和 never
type T5 = Parameters<any>;
// type T5 = unknown[]
type T6 = Parameters<never>;
// type T6 = never

// 下面这样传参是会报错的
type T7 = Parameters<string>;
type T8 = Parameters<Function>;
// 源码定义
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never

可以看到限制了函数类型,然后 ...args 取参数和 js 中的用法是一样的,infer 表示待推断的类型变量,打断出 ...args 取到的类型赋值给 P

ReturnType

ReturnType<T>:作用是获取函数返回值的类型。T 为函数

示例:

declare function f1(): { a: number; b: string };

type T1 = ReturnType<() => string>;
// type T1 = string

type T2 = ReturnType<(s: string) => void>;
// type T2 = void

type T3 = ReturnType<<T>() => T>;
// type T3 = unknown

type T4 = ReturnType<<T extends U, U extends number[]>() => T>;
// type T4 = number[]

type T5 = ReturnType<typeof f1>;
// type T5 = {
//     a: number;
//     b: string;
// }

// any 和 never
type T6 = ReturnType<any>;
// type T6 = any
type T7 = ReturnType<never>;
// type T7 = never

// 下面这样是不行的
type T8 = ReturnType<string>;
type T9 = ReturnType<Function>;
// 源码定义
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any

可以看到源码定义上和 Parameters 是基本一样的,只是把类型推断的参数换成返回值了

ConstructorParameters/InstanceType

我们知道 ParametersReturnType 这一对是获取普通/箭头函数的参数类型集合以及返回值类型的了,还有一对组合ConstructorParametersInstanceType 是获取构造函数的参数类型集合以及返回值类型的,和上面的比较类似我就放到一起了

Uppercase/Lowercase

这俩儿的作用是转换全部字母大小写

type T1 = Uppercase<"abcd">
// type T1 = "ABCD"

type T2 = Lowercase<"ABCD">
// type T2 = "abcd"

Capitalize/Uncapitalize

这俩儿的作用是转换首字母大小写

type T1 = Capitalize<"abcd efg">
// type T1 = "Abcd efg"

type T2 = Uncapitalize<"ABCD EFG">
// type T2 = "aBCD EFG"

练习四

请实现一个类型,把对象类型中的属性名换成大写,需要注意的是对象属性名支持 string | number | symbol 三种类型

type User1 = {
    name: string
    age: number
    18: number
}

// 实现如下,只需调用现在的工具类型 Uppercase 就行了

// 先取出所有字符串属性的出来,再处理返回 { NAME: string, AGE: number }
// type T1<T> = { [P in keyof T & string as Uppercase<P>]: T[P] }
// 只处理字符串属性的,其他正常返回
type T1<T> = { [P in keyof T as P extends string ? Uppercase<P> : P]: T[P] }

type T2 = T1<User1>
// type T2 = {
//     NAME: string;
//     AGE: number;
//     18: number
// }

综合练习

请实现一个类型,可以把下划线属性名的对象,换成驼峰属性名的对象。这个就没有现成的工具类型调用了,所以需要我们额外实现一个

这个练习用到了本文中的很多知识,先自己写一下咯

type User1 = {
    my_name: string
    my_age_type: number // 多个下划线
    my_children: {
        my_boy: number
        my_girl: number
    }
}

// 实现如下
type T1<T> = T extends string
 ? T extends `${infer A}_${infer B}`
  ? `${A}${T1<Capitalize<B>>}` // 这里有递归处理单个属性名多个下划线
  : T
 : T;
// 对象不递归
// type T2<T> = { [P in keyof T as T1<P>]: T[P] }
// 对象递归
type T2<T> = T extends object ? { [P in keyof T as T1<P>]: T2<T[P]> } : T

type T3 = T2<User1>
// type T3 = {
//     myName: string;
//     myAgeType: number;
//     myChildren: {
//         myBoy: number;
//         myGirl: number;
//     };
// }

这个练习用到了 extendsinferas循环递归,相信能更好地帮助我们理解和运用

结语

如果本文对你有一点点帮助,点个赞支持一下吧,你的每一个【赞】都是我创作的最大动力 ^_^

更多前端文章,或者加入前端交流群,欢迎关注公众号【前端快乐多】,大家一起共同交流和进步呀

参考资料

https://www.typescriptlang.org/docs/handbook/utility-types.html

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/B5a2ddSYktVNMGDv14J31Q

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237239次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8075次阅读
 目录