首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >“强类型”函数与许多冗余函数与类型记录的字符串枚举

“强类型”函数与许多冗余函数与类型记录的字符串枚举
EN

Stack Overflow用户
提问于 2022-05-15 20:35:41
回答 1查看 97关注 0票数 0

我在以下结构中有一个对象:

代码语言:javascript
复制
const geo = {
    europe: {
      germany: ['berlin', 'hamburg', 'cologne'],
      france: ['toulouse', 'paris', 'limoges'],
      italy: ['rome', 'venice', 'genoa'],
    },
    asia: {
      india: ['mumbai', 'rajkot', 'pune'],
      china: ['shenzhen', 'beijing', 'shanghai'],
      nepal: ['kohalpur', 'ghorahi', 'hetauda'],
    },
  };

我想写一个简单的函数,随机选择一个城市,给定的大陆和国家。虽然在我看来一个简单的实现是

代码语言:javascript
复制
const randomElement = (arr) => arr[Math.floor(Math.random() * arr.length)];
const pickCity = (continent, country) => randomElement(geo[continent][country])

// calling `pickCity()`
pickCity("europe", "france") // => we get one city at random, as requested

不过,我不知道这种实现是否属于“打得很厉害”函数的范畴,据说这是一种次优实践。

另一方面,如果我试图避免使用这些字符串参数,那么另一种方法将是更加冗长,而且不尊重干法原则:

代码语言:javascript
复制
const pickCityGermany = () => randomElement(geo.europe.germany)
const pickCityFrance = () => randomElement(geo.europe.france)
const pickCityItaly = () => randomElement(geo.europe.italy)
const pickCityIndia = () => randomElement(geo.asia.india)
const pickCityChina = () => randomElement(geo.asia.china)
const pickCityNepal = () => randomElement(geo.asia.nepal)

pickCity()确实是“令人心烦的类型”,还是我误解了这个概念?

更新

在下面@Bergie的回答之后,我意识到类型记录的enum很可能是键入pickCity()参数的适当解决方案,所以我在这里做了一个存根,但是下面,这仍然不是一个完全的解决方案。

我首先创建了两个enum,一个用于大陆,另一个用于国家:

代码语言:javascript
复制
// typescript
enum Continent {
    Europe = "europe",
    Asia = "asia"
}

enum Country {
    Germany = "germany",
    France = "france",
    Italy = "italy",
    India = "india",
    China = "china",
    Nepal = "nepal"
}

然而,正如@Bergi所写的,它们是相互依赖的,因为geo数据的结构方式。所以,我现在解决这个问题的唯一方法是输入any,这肯定不是我想要的解决方案:

代码语言:javascript
复制
type Geo = Record<Continent, any> // <~-~-~-~-~ `any` is :(

const geo: Geo = {
    europe: {
      germany: ['berlin', 'hamburg', 'cologne'],
      france: ['toulouse', 'paris', 'limoges'],
      italy: ['rome', 'venice', 'genoa'],
    },
    asia: {
      india: ['mumbai', 'rajkot', 'pune'],
      china: ['shenzhen', 'beijing', 'shanghai'],
      nepal: ['kohalpur', 'ghorahi', 'hetauda'],
    },
  };

const randomElement = (arr) => arr[Math.floor(Math.random() * arr.length)];
const pickCity2 = (continent: Continent, country: Country) => randomElement(geo[continent][country])

// calling pickCity2()
console.log(pickCity2(Continent.Europe, Country.Germany)) // => one German city at random

为什么我们不能简单地通过更改geo**?**来解开依赖关系

@Bergi问这个问题,因为这似乎是一种不必要的并发症。因此,如果我们有以下的geoSimpler,生活就会更容易一些:

代码语言:javascript
复制
type GeoSimpler = Record<Country, string[]>;

const geoSimpler: GeoSimpler = {
  germany: ['berlin', 'hamburg', 'cologne'],
  france: ['toulouse', 'paris', 'limoges'],
  italy: ['rome', 'venice', 'genoa'],
  india: ['mumbai', 'rajkot', 'pune'],
  china: ['shenzhen', 'beijing', 'shanghai'],
  nepal: ['kohalpur', 'ghorahi', 'hetauda'],
};
const pickCity3 = (country: Country) => randomElement(geoSimpler[country])
console.log(pickCity3(Country.France)) // 

不过,

我仍然想说明不能简化的数据结构。例如,考虑geoTwinCitiesAttractions

代码语言:javascript
复制
const geoTwinCitiesAttractions = {
  us: {
    cairo: ['U.S. Custom House', 'Cairo Public LIbrary', 'Magnolia Manor'],
    memphis: ['Graceland', 'National Civil Rights Museum', 'Beale Street'],
    saintPetersburg: ['The Dali Museum', 'Sunken Gardens', 'Chihuly Collection'],
    moscow: [],
    athens: ['Pleasant Hill Vineyards', 'Little Fish Brewing', 'Athens Farmers Market'],
  },
  greece: {
    athens: ['Acropolis of Athens', 'Parthenon', 'Mount Lycabettus'],
  },
  france: {
    paris: ['Eiffel Tower', 'Louvre Museum', 'Arc de Triomphe'],
  },
  russia: {
    saintPetersburg: ['State Hermitage Museum', 'Savior on the Spilled Blood', 'Winter Palace',
    ],
    moscow: ['Red Square', 'Bolshoi Theatre', 'Cathedral of Christ the Saviour'],
  },
  egypt: {
    cairo: ['Giza Necropolis', 'Mosque of Muhammad Ali', 'Salah Al-Din Al-Ayoubi Castle'],
    memphis: ['foo', 'bar', 'baz'],
  },
};

在这里,我们必须指明国家和城市,因为在不同的国家有同名的城市.那么,我们如何使用enum来避免“严重输入”pickAttraction()呢?

代码语言:javascript
复制
const pickAttraction = (country: string, city: string) => randomElement(geoTwinCitiesAttractions[country][city])
EN

回答 1

Stack Overflow用户

发布于 2022-05-15 21:40:47

是的,如果您真的考虑将任意字符串传递给pickCity,那么是“非常类型的”。pickCity('africa', 'sudan')在当前数据结构中失败。更糟糕的是,pickCity('sun', 'earth')pickCity('major:Scholz', 'population:>10000')pickCity('','ivqu ioqwe h')根本就没有意义。

但是,如果不将任意字符串传递给它,只将大陆名称传递给第一个参数,而只将状态名称传递给第一个参数,则没关系。使用枚举类型将更适合于键入这些参数。但是,由于您具体询问的是JavaScript,所以没有枚举类型(也没有类型声明),如果需要动态选择选项,那么在运行时使用字符串的是最可行的解决方案。但是您的心智模型(以及注释和文档)必须将它们视为枚举,或者作为一组允许的字符串。

(另一个与“字体”无关的问题是,参数相互依赖。pickCity('america', 'germany')不起作用,因为德国不在美国。你真的需要这块大陆吗?)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72251993

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档